<commit_before>#![feature(alloc_system)]
extern crate alloc_system;

use std::collections::HashSet;
use std::hash::{Hash, Hasher};

pub fn puzzle(input: &str) -> u32 {
    let mut floor1 = HashSet::new();
    floor1.insert(Component::Generator(Element::Thulium));
    floor1.insert(Component::Microchip(Element::Thulium));
    floor1.insert(Component::Generator(Element::Plutonium));
    floor1.insert(Component::Generator(Element::Strontium));

    let mut floor2 = HashSet::new();
    floor2.insert(Component::Microchip(Element::Plutonium));
    floor2.insert(Component::Microchip(Element::Strontium));

    let mut floor3 = HashSet::new();
    floor3.insert(Component::Generator(Element::Promethium));
    floor3.insert(Component::Microchip(Element::Promethium));
    floor3.insert(Component::Generator(Element::Ruthenium));
    floor3.insert(Component::Microchip(Element::Ruthenium));

    // let mut floor1 = HashSet::new();
    // floor1.insert(Component::Microchip(Element::Hydrogen));
    // floor1.insert(Component::Microchip(Element::Lithium));
    //
    // let mut floor2 = HashSet::new();
    // floor2.insert(Component::Generator(Element::Hydrogen));
    //
    // let mut floor3 = HashSet::new();
    // floor3.insert(Component::Generator(Element::Lithium));

    let initial_building_state = BuildingState {
        elevator_floor: 0,
        floors: [
            floor1,
            floor2,
            floor3,
            HashSet::new(),
        ],
    };
    let initial_world_state = WorldState {
        steps: 0,
        building: initial_building_state.clone()
    };
    let mut queue = vec![initial_world_state];
    let mut seen = HashSet::new();
    seen.insert(initial_building_state);
    let mut steps = 0;

    while !queue.is_empty() {
        let world = queue.remove(0);

        if world.steps != steps {
            println!("{} step(s), queue: {}", world.steps, queue.len());
            steps = world.steps;
        }

        seen.insert(world.building.clone());

        if world.steps == 100 {
            panic!("too far!");
        }
        if world.in_end_state() {
            return world.steps;
        }

        let mut valid_next_moves = world.next_moves(&seen);
        queue.append(&mut valid_next_moves);
    }

    panic!("Exhausted all possible moves without finding end condition!");
}

#[derive(Debug)]
pub struct WorldState {
    steps: u32,
    building: BuildingState,
}

impl WorldState {
    pub fn in_end_state(&self) -> bool {
        self.building.in_end_state()
    }

    pub fn next_moves(&self, seen: &HashSet<BuildingState>) -> Vec<WorldState> {
        self.building.next_moves(seen).into_iter().map(|b| {
            WorldState {
                steps: self.steps + 1,
                building: b,
            }
        }).collect()
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd, Ord, Hash)]
pub enum Component {
    Microchip(Element),
    Generator(Element),
}

impl Component {
    fn is_fried(&self, others: &HashSet<Component>) -> bool {
        match *self {
            Component::Generator(my_element) => {
                // There's microchip(s) that are not my element
                // and no generator that is that microchip's element
                (*others).iter().any(|&c|
                    match c {
                        Component::Microchip(e) if e != my_element && !(*others).contains(&Component::Generator(e)) => true,
                        _ => false,
                    }
                )
            },
            Component::Microchip(my_element) => {
                // There's some generator that is not my element
                (*others).iter().find(|&c| {
                    match *c {
                        Component::Generator(e) if e != my_element => true,
                        _ => false,
                    }
                }).is_some() &&
                // There is no generator that is my element
                (*others).iter().find(|&c| {
                    match *c {
                        Component::Generator(e) if e == my_element => true,
                        _ => false,
                    }
                }).is_none()
            }
        }
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd, Ord, Hash)]
pub enum Element {
    Hydrogen,
    Lithium,
    Thulium,
    Plutonium,
    Strontium,
    Promethium,
    Ruthenium,
}

#[derive(Debug, PartialEq, Eq)]
pub struct BuildingState {
    elevator_floor: usize,
    floors: [HashSet<Component>; 4],
}

impl Hash for BuildingState {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.elevator_floor.hash(state);
        for floor in self.floors.iter() {
            let mut components: Vec<&Component> = floor.iter().collect();
            components.sort();
            components.hash(state);
        }
    }
}

impl Clone for BuildingState {
    fn clone(&self) -> BuildingState {
        BuildingState {
            elevator_floor: self.elevator_floor,
            floors: [
                self.floors[0].clone(),
                self.floors[1].clone(),
                self.floors[2].clone(),
                self.floors[3].clone(),
            ]
        }
    }
}

impl BuildingState {
    pub fn in_end_state(&self) -> bool {
        self.floors[0].is_empty() &&
            self.floors[1].is_empty() &&
            self.floors[2].is_empty()
    }

    pub fn next_floors(&self) -> Vec<usize> {
        match self.elevator_floor {
            0 => vec![1],
            1 => vec![0, 2],
            2 => vec![1, 3],
            3 => vec![2],
            other => panic!("How did you get on floor {}, elevator?", other),
        }
    }

    pub fn elevator_combos(&self) -> Vec<Vec<Component>> {
        // It sure would be nice to be able to have HashSet<HashSet<Component>>
        // here so that I don't have to filter out duplicates myself.

        let mut result = vec![];
        let mut components = self.floors[self.elevator_floor].iter();
        while let Some(&component) = components.next() {
            // Could take just this item on the elevator
            result.push(vec![component]);
            // Could take this item and one other, if they don't fry
            for &remaining_component in components.clone() {
                let mut hs = HashSet::new();
                hs.insert(remaining_component);
                if !component.is_fried(&hs) {
                    result.push(vec![component, remaining_component]);
                }
            }
        }
        result
    }

    pub fn next_moves(&self, seen: &HashSet<BuildingState>)
                      -> Vec<BuildingState> {
        let mut valid_next_moves = vec![];
        for next_floor in self.next_floors() {
            for combo in self.elevator_combos() {
                let mut bs = (*self).clone();
                for &c in combo.iter() {
                    bs.floors[self.elevator_floor].remove(&c);
                    bs.floors[next_floor].insert(c);
                }
                bs.elevator_floor = next_floor;
                if !bs.has_fried_chips() && !seen.contains(&bs) {
                    valid_next_moves.push(bs);
                }
            }
        }
        valid_next_moves
    }

    pub fn has_fried_chips(&self) -> bool {
        for floor in self.floors.iter() {
            for component in floor {
                // This is doing an extra comparison to itself :shrug:
                if component.is_fried(floor) {
                    return true
                }
            }
        }
        false
    }
}

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

    #[test]
    fn not_in_end_state() {
        let mut floor1 = HashSet::new();
        floor1.insert(Component::Microchip(Element::Hydrogen));
        floor1.insert(Component::Microchip(Element::Lithium));

        let mut floor2 = HashSet::new();
        floor2.insert(Component::Generator(Element::Hydrogen));

        let mut floor3 = HashSet::new();
        floor3.insert(Component::Generator(Element::Lithium));

        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    floor1,
                    floor2,
                    floor3,
                    HashSet::new(),
                ],
            }
        };
        assert!( ! world_state.in_end_state() );
    }

    #[test]
    fn in_end_state() {
        let mut floor4 = HashSet::new();
        floor4.insert(Component::Generator(Element::Hydrogen));
        floor4.insert(Component::Microchip(Element::Hydrogen));
        floor4.insert(Component::Microchip(Element::Lithium));
        floor4.insert(Component::Generator(Element::Lithium));
        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    HashSet::new(),
                    HashSet::new(),
                    HashSet::new(),
                    floor4,
                ],
            }
        };

        assert!(world_state.in_end_state());
    }

    #[test]
    fn two_microchips_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Microchip(Element::Lithium));
        assert!(
            ! Component::Microchip(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn microchip_alone_not_fried() {
        assert!(
            ! Component::Microchip(Element::Hydrogen).is_fried(
                &HashSet::new()
            )
        )
    }

    #[test]
    fn microchip_with_itself_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Microchip(Element::Hydrogen));

        assert!(
            ! Component::Microchip(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn two_generators_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Lithium));

        assert!(
            ! Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn microchip_and_matching_generator_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Hydrogen));

        assert!(
            ! Component::Microchip(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn microchip_attached_to_matching_generator_not_fried_by_other_generator() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));

        assert!(
            ! Component::Microchip(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn microchip_without_its_generator_with_another_generator_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Lithium));

        assert!(
            Component::Microchip(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn generator_with_a_microchip_without_its_generator_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Microchip(Element::Lithium));

        assert!(
            Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn generator_with_a_generator_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        assert!(
            ! Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn generator_with_its_microchip_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Microchip(Element::Hydrogen));

        assert!(
            ! Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn generator_with_itself_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Hydrogen));

        assert!(
            ! Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn generator_with_a_microchip_with_its_generator_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Microchip(Element::Lithium));

        assert!(
            ! Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }
}
<commit_msg>Switch the queue to VecDeque<commit_after>#![feature(alloc_system)]
extern crate alloc_system;

use std::collections::{HashSet, VecDeque};
use std::hash::{Hash, Hasher};

pub fn puzzle(input: &str) -> u32 {
    // let mut floor1 = HashSet::new();
    // floor1.insert(Component::Generator(Element::Thulium));
    // floor1.insert(Component::Microchip(Element::Thulium));
    // floor1.insert(Component::Generator(Element::Plutonium));
    // floor1.insert(Component::Generator(Element::Strontium));
    //
    // let mut floor2 = HashSet::new();
    // floor2.insert(Component::Microchip(Element::Plutonium));
    // floor2.insert(Component::Microchip(Element::Strontium));
    //
    // let mut floor3 = HashSet::new();
    // floor3.insert(Component::Generator(Element::Promethium));
    // floor3.insert(Component::Microchip(Element::Promethium));
    // floor3.insert(Component::Generator(Element::Ruthenium));
    // floor3.insert(Component::Microchip(Element::Ruthenium));

    let mut floor1 = HashSet::new();
    floor1.insert(Component::Microchip(Element::Hydrogen));
    floor1.insert(Component::Microchip(Element::Lithium));

    let mut floor2 = HashSet::new();
    floor2.insert(Component::Generator(Element::Hydrogen));

    let mut floor3 = HashSet::new();
    floor3.insert(Component::Generator(Element::Lithium));

    let initial_building_state = BuildingState {
        elevator_floor: 0,
        floors: [
            floor1,
            floor2,
            floor3,
            HashSet::new(),
        ],
    };
    let initial_world_state = WorldState {
        steps: 0,
        building: initial_building_state.clone()
    };
    let mut queue = VecDeque::new();
    queue.push_back(initial_world_state);
    let mut seen = HashSet::new();
    seen.insert(initial_building_state);
    let mut steps = 0;

    while let Some(world) = queue.pop_front() {
        if world.steps != steps {
            println!("{} step(s), queue: {}", world.steps, queue.len());
            steps = world.steps;
        }

        seen.insert(world.building.clone());

        if world.steps == 100 {
            panic!("too far!");
        }
        if world.in_end_state() {
            return world.steps;
        }

        for next_move in world.next_moves(&seen) {
            queue.push_back(next_move);
        }
    }

    panic!("Exhausted all possible moves without finding end condition!");
}

#[derive(Debug)]
pub struct WorldState {
    steps: u32,
    building: BuildingState,
}

impl WorldState {
    pub fn in_end_state(&self) -> bool {
        self.building.in_end_state()
    }

    pub fn next_moves(&self, seen: &HashSet<BuildingState>) -> Vec<WorldState> {
        self.building.next_moves(seen).into_iter().map(|b| {
            WorldState {
                steps: self.steps + 1,
                building: b,
            }
        }).collect()
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd, Ord, Hash)]
pub enum Component {
    Microchip(Element),
    Generator(Element),
}

impl Component {
    fn is_fried(&self, others: &HashSet<Component>) -> bool {
        match *self {
            Component::Generator(my_element) => {
                // There's microchip(s) that are not my element
                // and no generator that is that microchip's element
                (*others).iter().any(|&c|
                    match c {
                        Component::Microchip(e) if e != my_element && !(*others).contains(&Component::Generator(e)) => true,
                        _ => false,
                    }
                )
            },
            Component::Microchip(my_element) => {
                // There's some generator that is not my element
                (*others).iter().find(|&c| {
                    match *c {
                        Component::Generator(e) if e != my_element => true,
                        _ => false,
                    }
                }).is_some() &&
                // There is no generator that is my element
                (*others).iter().find(|&c| {
                    match *c {
                        Component::Generator(e) if e == my_element => true,
                        _ => false,
                    }
                }).is_none()
            }
        }
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug, PartialOrd, Ord, Hash)]
pub enum Element {
    Hydrogen,
    Lithium,
    Thulium,
    Plutonium,
    Strontium,
    Promethium,
    Ruthenium,
}

#[derive(Debug, PartialEq, Eq)]
pub struct BuildingState {
    elevator_floor: usize,
    floors: [HashSet<Component>; 4],
}

impl Hash for BuildingState {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.elevator_floor.hash(state);
        for floor in self.floors.iter() {
            let mut components: Vec<&Component> = floor.iter().collect();
            components.sort();
            components.hash(state);
        }
    }
}

impl Clone for BuildingState {
    fn clone(&self) -> BuildingState {
        BuildingState {
            elevator_floor: self.elevator_floor,
            floors: [
                self.floors[0].clone(),
                self.floors[1].clone(),
                self.floors[2].clone(),
                self.floors[3].clone(),
            ]
        }
    }
}

impl BuildingState {
    pub fn in_end_state(&self) -> bool {
        self.floors[0].is_empty() &&
            self.floors[1].is_empty() &&
            self.floors[2].is_empty()
    }

    pub fn next_floors(&self) -> Vec<usize> {
        match self.elevator_floor {
            0 => vec![1],
            1 => vec![0, 2],
            2 => vec![1, 3],
            3 => vec![2],
            other => panic!("How did you get on floor {}, elevator?", other),
        }
    }

    pub fn elevator_combos(&self) -> Vec<Vec<Component>> {
        // It sure would be nice to be able to have HashSet<HashSet<Component>>
        // here so that I don't have to filter out duplicates myself.

        let mut result = vec![];
        let mut components = self.floors[self.elevator_floor].iter();
        while let Some(&component) = components.next() {
            // Could take just this item on the elevator
            result.push(vec![component]);
            // Could take this item and one other, if they don't fry
            for &remaining_component in components.clone() {
                let mut hs = HashSet::new();
                hs.insert(remaining_component);
                if !component.is_fried(&hs) {
                    result.push(vec![component, remaining_component]);
                }
            }
        }
        result
    }

    pub fn next_moves(&self, seen: &HashSet<BuildingState>)
                      -> Vec<BuildingState> {
        let mut valid_next_moves = vec![];
        for next_floor in self.next_floors() {
            for combo in self.elevator_combos() {
                let mut bs = (*self).clone();
                for &c in combo.iter() {
                    bs.floors[self.elevator_floor].remove(&c);
                    bs.floors[next_floor].insert(c);
                }
                bs.elevator_floor = next_floor;
                if !bs.has_fried_chips() && !seen.contains(&bs) {
                    valid_next_moves.push(bs);
                }
            }
        }
        valid_next_moves
    }

    pub fn has_fried_chips(&self) -> bool {
        for floor in self.floors.iter() {
            for component in floor {
                // This is doing an extra comparison to itself :shrug:
                if component.is_fried(floor) {
                    return true
                }
            }
        }
        false
    }
}

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

    #[test]
    fn not_in_end_state() {
        let mut floor1 = HashSet::new();
        floor1.insert(Component::Microchip(Element::Hydrogen));
        floor1.insert(Component::Microchip(Element::Lithium));

        let mut floor2 = HashSet::new();
        floor2.insert(Component::Generator(Element::Hydrogen));

        let mut floor3 = HashSet::new();
        floor3.insert(Component::Generator(Element::Lithium));

        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    floor1,
                    floor2,
                    floor3,
                    HashSet::new(),
                ],
            }
        };
        assert!( ! world_state.in_end_state() );
    }

    #[test]
    fn in_end_state() {
        let mut floor4 = HashSet::new();
        floor4.insert(Component::Generator(Element::Hydrogen));
        floor4.insert(Component::Microchip(Element::Hydrogen));
        floor4.insert(Component::Microchip(Element::Lithium));
        floor4.insert(Component::Generator(Element::Lithium));
        let world_state = WorldState {
            steps: 0,
            building: BuildingState {
                elevator_floor: 0,
                floors: [
                    HashSet::new(),
                    HashSet::new(),
                    HashSet::new(),
                    floor4,
                ],
            }
        };

        assert!(world_state.in_end_state());
    }

    #[test]
    fn two_microchips_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Microchip(Element::Lithium));
        assert!(
            ! Component::Microchip(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn microchip_alone_not_fried() {
        assert!(
            ! Component::Microchip(Element::Hydrogen).is_fried(
                &HashSet::new()
            )
        )
    }

    #[test]
    fn microchip_with_itself_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Microchip(Element::Hydrogen));

        assert!(
            ! Component::Microchip(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn two_generators_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Lithium));

        assert!(
            ! Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn microchip_and_matching_generator_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Hydrogen));

        assert!(
            ! Component::Microchip(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn microchip_attached_to_matching_generator_not_fried_by_other_generator() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Generator(Element::Hydrogen));

        assert!(
            ! Component::Microchip(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn microchip_without_its_generator_with_another_generator_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Lithium));

        assert!(
            Component::Microchip(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn generator_with_a_microchip_without_its_generator_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Microchip(Element::Lithium));

        assert!(
            Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn generator_with_a_generator_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        assert!(
            ! Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn generator_with_its_microchip_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Microchip(Element::Hydrogen));

        assert!(
            ! Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn generator_with_itself_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Hydrogen));

        assert!(
            ! Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }

    #[test]
    fn generator_with_a_microchip_with_its_generator_not_fried() {
        let mut hs = HashSet::new();
        hs.insert(Component::Generator(Element::Lithium));
        hs.insert(Component::Microchip(Element::Lithium));

        assert!(
            ! Component::Generator(Element::Hydrogen).is_fried(
                &hs
            )
        )
    }
}
<|endoftext|>


<commit_before>//! A library the provides a safe Rust wrapper for
//! [Stacy's Pathetically Simple Parsing System](https://github.com/sprowell/spsps).

extern crate libc;
#[macro_use]
extern crate log;
extern crate env_logger as logger;
use log::LogLevel;
use std::io::prelude::*;
use std::str;
use std::char;
use std::ptr;
use std::path::Path;
use std::fs::File;
use std::ffi::CStr;
use std::ffi::CString;

/// For now we're treating spsps_loc_ as an opaque pointer.
#[allow(non_camel_case_types)]
enum spsps_loc_ {}
/// An opaque type for spsps_errno. Currently unused.
#[allow(non_camel_case_types)]
enum spsps_errno {}

/*
#[repr(C)]
struct Loc{
    name: *const libc::c_char,
    line: u32,
    column: u32,
}
*/

/// This is for the opaque C pointer to spsps_parser_
#[allow(non_camel_case_types)]
enum spsps_parser_ {}
/// This is the safe abstraction over a spsps parser.
#[derive(Debug)]
#[allow(raw_pointer_derive)]
pub struct Parser{
    /// The raw pointer to a C spsps parser.
    _ptr: *mut spsps_parser_,
    /// A raw pointer a C file stream. May be null for stdin.
    _fd: *mut libc::FILE
}

#[derive(Debug)]
#[allow(raw_pointer_derive)]
/// A safe abstruction over a raw spsps_loc_ pointer.
pub struct Loc{
    /// The *mut spsps_loc_pointer.
    ptr: *mut spsps_loc_
}

#[link(name = "spsps")]
extern{
    //This returns an owned Parser
    fn spsps_new(name: *const libc::c_char, stream: *mut libc::FILE) -> *mut spsps_parser_;
    fn spsps_free(parser: *mut spsps_parser_);
    //This returns an owned C string.
    fn spsps_loc_to_string(loc: *mut spsps_loc_) -> *mut libc::c_char;
    //This returns a borrowed string
    fn spsps_printchar(xch: libc::c_char) -> *mut libc::c_char;
    fn spsps_consume(parser: *mut spsps_parser_) -> libc::c_char;
    fn spsps_consume_n(parser: *mut spsps_parser_, n: libc::size_t);
    fn spsps_consume_whitespace(parser: *mut spsps_parser_);
    //Not sure what return type to use for bool
    fn spsps_eof(parser: *mut spsps_parser_) -> libc::c_int;
    //This returns an owned Loc
    fn spsps_loc(parser: *mut spsps_parser_) -> *mut spsps_loc_;
    fn spsps_peek(parser: *mut spsps_parser_) -> libc::c_char;
    fn spsps_peek_n(parser: *mut spsps_parser_, n: libc::size_t) -> *mut libc::c_char;
    fn spsps_peek_str(parser: *mut spsps_parser_, next: *const libc::c_char) -> libc::c_int;
    fn spsps_peek_and_consume(parser: *mut spsps_parser_, next: *const libc::c_char) -> libc::c_int;
}

impl Parser{
    /// Create a new `Parser` with zero configuration. Name will use the default from libspsps,
    /// and will read from stdin.
    pub fn new() -> Parser {
        unsafe{
            Parser{
                _ptr: spsps_new(ptr::null(), ptr::null_mut()),
                _fd: ptr::null_mut()
            }
         }
    }

    /// Create a Parser that will read from the file given in `path`. If `None` is given for `name`
    /// the default spsps parser name will be used.
    pub fn from_file(name: Option<&str>, path: &Path) -> Parser {
        unsafe{
            let c_path = CString::new(path.to_str().unwrap()).unwrap().as_ptr();
            debug!("from_file path: {:?}", CString::new(path.to_str().unwrap()).unwrap());
            let fd = libc::funcs::c95::stdio::fopen(c_path,  CString::new("r").unwrap().as_ptr());
            if fd.is_null() {
                panic!("Unable to open file to parse.");
            }
            match name{
                Some(n) => Parser{
                        _ptr: spsps_new(CString::new(n).unwrap().as_ptr(), fd),
                        _fd: fd
                    },
                None => Parser{
                        _ptr: spsps_new(ptr::null(), fd),
                        _fd: fd
                    }
            }
         }
    }

    /// Consume and return the next character in the stream.
    pub fn consume(&self) -> String {
        unsafe {
            char::from_u32(spsps_consume(self._ptr) as u32).unwrap().to_string()
        }
    }

    /// Consume and discard the next `n` characters from the stream.
    pub fn consume_n(&self, n: usize){
        unsafe { spsps_consume_n(self._ptr, n as libc::size_t); }
    }

    /// Consume and discard all whitespace.  When this method returns the next
    /// character is the first non-whitespace character, or the end of file has
    /// been reached.
    pub fn consume_whitespace(&self){
        unsafe { spsps_consume_whitespace(self._ptr); }
    }

    ///Determine if the end of file has been consumed.
    pub fn eof(&self) -> bool{
        unsafe { spsps_eof(self._ptr) as usize != 0 }
    }

    /// Get the current location in the stream.  This is the location of the next
    /// character to be read, unless the end of stream has been reached.
    pub fn get_loc(&self) -> Loc {
        unsafe{
            Loc { ptr: spsps_loc(self._ptr) }
        }
    }

    ///Peek and return the next character in the stream.  The character is not consumed.
    pub fn peek(&self) -> String{
        let c_char = unsafe { spsps_peek(self._ptr) };
        char::from_u32(c_char as u32).unwrap().to_string()
    }

    /// Peek ahead at the next few characters in the stream, and return them.  The
    /// The number of characters must be below the lookahead limit.  End of file causes the
    /// returned string to be populated by EOF characters.
    pub fn peek_n(&self, n: usize) -> String{
        let cstr = unsafe{ spsps_peek_n(self._ptr, n as libc::size_t) };
        let safe_cstr = unsafe { CStr::from_ptr(cstr) };
        let retval = str::from_utf8(safe_cstr.to_bytes()).unwrap_or("").to_owned();
        unsafe { libc::free(safe_cstr.as_ptr() as *mut libc::c_void); }
        return retval;
    }

    /// Peek ahead and determine if the next characters in the stream are the given
    /// characters, in sequence.  That is, the given string must be the next thing in the stream.
    pub fn peek_str(&self, needle: &str) -> bool {
        unsafe { spsps_peek_str(self._ptr, CString::new(needle).unwrap().as_ptr()) != 0 }
    }

    ///Peek ahead at the next few characters and if they are a given string, then
    /// consume them.  Otherwise leave the stream unchanged.
    pub fn peek_str_and_consume(&self, needle: &str) -> bool {
        unsafe { spsps_peek_and_consume(self._ptr, CString::new(needle).unwrap().as_ptr()) != 0 }
    }
}

impl Drop for Parser{
    fn drop(&mut self) {
        unsafe{
            if !self._ptr.is_null() { spsps_free(self._ptr); }
            if !self._fd.is_null() { libc::fclose(self._fd); }
        }
    }
}

impl ToString for Loc{
    ///Convert this location to a short string.
    fn to_string(&self) -> String{
        let tmp = unsafe { CStr::from_ptr(spsps_loc_to_string(self.ptr)) };
        let retval = str::from_utf8(tmp.to_bytes()).unwrap_or("").to_owned();
        unsafe {libc::free(tmp.as_ptr() as *mut libc::c_void);}
        retval
    }
}

impl Drop for Loc{
    fn drop(&mut self) {
        unsafe{ if !self.ptr.is_null() { libc::free(self.ptr as *mut libc::c_void); } }
    }
}

#[allow(dead_code)]
fn test_parser() -> Parser {
    Parser::from_file(Some("test"), &Path::new("./test/foo.txt"))
}

#[test]
fn test_from_file(){
    logger::init().unwrap();
    let p = test_parser();
    //fs::remove_file("foo.txt").unwrap();
    println!("{:?}", p);
}

#[test]
fn test_peek_n(){
    let p = test_parser();
    let first_chars = p.peek_n(4);
    println!("{}", first_chars);
    assert_eq!(first_chars, "This");
}

#[test]
fn test_peek(){
    let p = test_parser();
    let first_char = p.peek();
    println!("{:?}", first_char);
    assert_eq!(first_char, "T");
}

#[test]
fn test_consume(){
    let p = test_parser();
    let first_char = p.consume();
    println!("{}", first_char);
    assert_eq!(first_char, "T");
}

#[test]
fn test_loc_to_string(){
    let p = test_parser();
    let location = p.get_loc();
    let loc_string = location.to_string();
    println!("{}",loc_string);
    assert_eq!(loc_string, "test:1:1");
}

#[test]
fn test_peek_consume(){
    let parser = test_parser();
    let p = parser.peek();
    let c = parser.consume();
    assert_eq!(p, c);
}
<commit_msg>All implemented library wrappers should have a small test case now.<commit_after>//! A library the provides a safe Rust wrapper for
//! [Stacy's Pathetically Simple Parsing System](https://github.com/sprowell/spsps).

extern crate libc;
#[macro_use]
extern crate log;
extern crate env_logger as logger;
use log::LogLevel;
use std::io::prelude::*;
use std::str;
use std::char;
use std::ptr;
use std::path::Path;
use std::fs::File;
use std::ffi::CStr;
use std::ffi::CString;

/// For now we're treating spsps_loc_ as an opaque pointer.
#[allow(non_camel_case_types)]
enum spsps_loc_ {}
/// An opaque type for spsps_errno. Currently unused.
#[allow(non_camel_case_types)]
enum spsps_errno {}

/*
#[repr(C)]
struct Loc{
    name: *const libc::c_char,
    line: u32,
    column: u32,
}
*/

/// This is for the opaque C pointer to spsps_parser_
#[allow(non_camel_case_types)]
enum spsps_parser_ {}
/// This is the safe abstraction over a spsps parser.
#[derive(Debug)]
#[allow(raw_pointer_derive)]
pub struct Parser{
    /// The raw pointer to a C spsps parser.
    _ptr: *mut spsps_parser_,
    /// A raw pointer a C file stream. May be null for stdin.
    _fd: *mut libc::FILE
}

#[derive(Debug)]
#[allow(raw_pointer_derive)]
/// A safe abstruction over a raw spsps_loc_ pointer.
pub struct Loc{
    /// The *mut spsps_loc_pointer.
    ptr: *mut spsps_loc_
}

#[link(name = "spsps")]
extern{
    //This returns an owned Parser
    fn spsps_new(name: *const libc::c_char, stream: *mut libc::FILE) -> *mut spsps_parser_;
    fn spsps_free(parser: *mut spsps_parser_);
    //This returns an owned C string.
    fn spsps_loc_to_string(loc: *mut spsps_loc_) -> *mut libc::c_char;
    //This returns a borrowed string
    fn spsps_printchar(xch: libc::c_char) -> *mut libc::c_char;
    fn spsps_consume(parser: *mut spsps_parser_) -> libc::c_char;
    fn spsps_consume_n(parser: *mut spsps_parser_, n: libc::size_t);
    fn spsps_consume_whitespace(parser: *mut spsps_parser_);
    //Not sure what return type to use for bool
    fn spsps_eof(parser: *mut spsps_parser_) -> libc::c_int;
    //This returns an owned Loc
    fn spsps_loc(parser: *mut spsps_parser_) -> *mut spsps_loc_;
    fn spsps_peek(parser: *mut spsps_parser_) -> libc::c_char;
    fn spsps_peek_n(parser: *mut spsps_parser_, n: libc::size_t) -> *mut libc::c_char;
    fn spsps_peek_str(parser: *mut spsps_parser_, next: *const libc::c_char) -> libc::c_int;
    fn spsps_peek_and_consume(parser: *mut spsps_parser_, next: *const libc::c_char) -> libc::c_int;
}

impl Parser{
    /// Create a new `Parser` with zero configuration. Name will use the default from libspsps,
    /// and will read from stdin.
    pub fn new() -> Parser {
        unsafe{
            Parser{
                _ptr: spsps_new(ptr::null(), ptr::null_mut()),
                _fd: ptr::null_mut()
            }
         }
    }

    /// Create a Parser that will read from the file given in `path`. If `None` is given for `name`
    /// the default spsps parser name will be used.
    pub fn from_file(name: Option<&str>, path: &Path) -> Parser {
        unsafe{
            let c_path = CString::new(path.to_str().unwrap()).unwrap().as_ptr();
            debug!("from_file path: {:?}", CString::new(path.to_str().unwrap()).unwrap());
            let fd = libc::funcs::c95::stdio::fopen(c_path,  CString::new("r").unwrap().as_ptr());
            if fd.is_null() {
                panic!("Unable to open file to parse.");
            }
            match name{
                Some(n) => Parser{
                        _ptr: spsps_new(CString::new(n).unwrap().as_ptr(), fd),
                        _fd: fd
                    },
                None => Parser{
                        _ptr: spsps_new(ptr::null(), fd),
                        _fd: fd
                    }
            }
         }
    }

    /// Consume and return the next character in the stream.
    pub fn consume(&self) -> String {
        unsafe {
            char::from_u32(spsps_consume(self._ptr) as u32).unwrap().to_string()
        }
    }

    /// Consume and discard the next `n` characters from the stream.
    pub fn consume_n(&self, n: usize){
        unsafe { spsps_consume_n(self._ptr, n as libc::size_t); }
    }

    /// Consume and discard all whitespace.  When this method returns the next
    /// character is the first non-whitespace character, or the end of file has
    /// been reached.
    pub fn consume_whitespace(&self){
        unsafe { spsps_consume_whitespace(self._ptr); }
    }

    ///Determine if the end of file has been consumed.
    pub fn at_eof(&self) -> bool{
        unsafe { spsps_eof(self._ptr) as usize != 0 }
    }

    /// Get the current location in the stream.  This is the location of the next
    /// character to be read, unless the end of stream has been reached.
    pub fn get_loc(&self) -> Loc {
        unsafe{
            Loc { ptr: spsps_loc(self._ptr) }
        }
    }

    ///Peek and return the next character in the stream.  The character is not consumed.
    pub fn peek(&self) -> String{
        let c_char = unsafe { spsps_peek(self._ptr) };
        char::from_u32(c_char as u32).unwrap().to_string()
    }

    /// Peek ahead at the next few characters in the stream, and return them.  The
    /// The number of characters must be below the lookahead limit.  End of file causes the
    /// returned string to be populated by EOF characters.
    pub fn peek_n(&self, n: usize) -> String{
        let cstr = unsafe{ spsps_peek_n(self._ptr, n as libc::size_t) };
        let safe_cstr = unsafe { CStr::from_ptr(cstr) };
        let retval = str::from_utf8(safe_cstr.to_bytes()).unwrap_or("").to_owned();
        unsafe { libc::free(safe_cstr.as_ptr() as *mut libc::c_void); }
        return retval;
    }

    /// Peek ahead and determine if the next characters in the stream are the given
    /// characters, in sequence.  That is, the given string must be the next thing in the stream.
    pub fn peek_str(&self, needle: &str) -> bool {
        unsafe { spsps_peek_str(self._ptr, CString::new(needle).unwrap().as_ptr()) != 0 }
    }

    ///Peek ahead at the next few characters and if they are a given string, then
    /// consume them.  Otherwise leave the stream unchanged.
    pub fn peek_str_and_consume(&self, needle: &str) -> bool {
        unsafe { spsps_peek_and_consume(self._ptr, CString::new(needle).unwrap().as_ptr()) != 0 }
    }
}

impl Drop for Parser{
    fn drop(&mut self) {
        unsafe{
            if !self._ptr.is_null() { spsps_free(self._ptr); }
            if !self._fd.is_null() { libc::fclose(self._fd); }
        }
    }
}

impl ToString for Loc{
    ///Convert this location to a short string.
    fn to_string(&self) -> String{
        let tmp = unsafe { CStr::from_ptr(spsps_loc_to_string(self.ptr)) };
        let retval = str::from_utf8(tmp.to_bytes()).unwrap_or("").to_owned();
        unsafe {libc::free(tmp.as_ptr() as *mut libc::c_void);}
        retval
    }
}

impl Drop for Loc{
    fn drop(&mut self) {
        unsafe{ if !self.ptr.is_null() { libc::free(self.ptr as *mut libc::c_void); } }
    }
}

#[allow(dead_code)]
fn test_parser() -> Parser {
    Parser::from_file(Some("test"), &Path::new("./test/foo.txt"))
}

#[test]
fn test_from_file(){
    logger::init().unwrap();
    let p = test_parser();
    //fs::remove_file("foo.txt").unwrap();
    println!("{:?}", p);
}

#[test]
fn test_peek_n(){
    let p = test_parser();
    let first_chars = p.peek_n(4);
    println!("{}", first_chars);
    assert_eq!(first_chars, "This");
}

#[test]
fn test_peek(){
    let p = test_parser();
    let first_char = p.peek();
    println!("{}", first_char);
    assert_eq!(first_char, "T");
}

#[test]
fn test_consume_n(){
    let p = test_parser();
    p.consume_n(3);
    let next_char = p.peek();
    println!("{}", next_char);
    assert_eq!(next_char, "s");
}

#[test]
fn test_consume_whitespace(){
    let p = test_parser();
    p.consume_n(4);
    p.consume_whitespace();
    let next_char = p.peek();
    println!("{}", next_char);
    assert_eq!(next_char, "i");
}

#[test]
fn test_consume(){
    let p = test_parser();
    let first_char = p.consume();
    println!("{}", first_char);
    assert_eq!(first_char, "T");
}

#[test]
fn test_loc_to_string(){
    let p = test_parser();
    let location = p.get_loc();
    let loc_string = location.to_string();
    println!("{}",loc_string);
    assert_eq!(loc_string, "test:1:1");
}

#[test]
fn test_peek_consume(){
    let parser = test_parser();
    let p = parser.peek();
    let c = parser.consume();
    assert_eq!(p, c);
}

#[test]
fn test_peek_str(){
    let parser = test_parser();
    assert!(parser.peek_str("This"));
}

#[test]
fn test_peek_str_and_consume(){
    let parser = test_parser();
    parser.peek_str_and_consume("This");
    assert_eq!(parser.peek(), " ");
}

#[test]
fn test_at_eof(){
    let parser = test_parser();
    assert!(!parser.at_eof());
    parser.consume_n(1000);
    assert!(parser.at_eof());
}
<|endoftext|>


<commit_before>extern crate socket;

use socket::{AF_INET, Socket, SOCK_DGRAM, IP_MULTICAST_TTL, IPPROTO_IP};
use std::collections::HashSet;
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::sync::{Arc, mpsc};
use std::thread;
use std::time::Instant;

#[derive(Debug)]
pub struct Discover {
    multicast_addr: SocketAddr,
    socket: Arc<Socket>
}

impl Discover {
    pub fn new() -> Self {
        Discover {
            multicast_addr: SocketAddr::from_str("239.255.255.250:1900").unwrap(),
            socket: Discover::create_socket()
        }
    }

    fn create_socket() -> Arc<Socket> {
        let socket = Socket::new(AF_INET, SOCK_DGRAM, 0).unwrap();
        let _ = socket.setsockopt(IPPROTO_IP, IP_MULTICAST_TTL, 4);

        Arc::new(socket)
    }

    fn send_search(&self) {
        let player_search = r#"M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:schemas-upnp-org:device:ZonePlayer:1"#.as_bytes();
        let _ = self.socket.sendto(player_search, 0, &self.multicast_addr);
    }

    pub fn start(&self, timeout: Option<u32>, device_count: Option<usize>) -> HashSet<IpAddr> {
        let timeout = match timeout {
            Some(value) => { value }
            None => 5
        };
        let device_count = match device_count {
            Some(value) => { value }
            None => std::u32::MAX as usize
        };

        let time = Instant::now();

        self.send_search();
        let socket = self.socket.clone();
        let mut devices: HashSet<IpAddr> = HashSet::new();
        while time.elapsed().as_secs() < timeout as u64 && devices.len() < device_count {
            let socket = socket.clone();
            let (sender, receiver) = mpsc::channel();
            let _ = thread::spawn(move ||
                {
                    match socket.recvfrom(1024, 0) {
                        Ok((__addr, _data)) => {
                            let _ = sender.send((__addr, _data));
                        }
                        Err(_) => {}
                    }
                }
            );

            let (_addr, data) = match receiver.recv_timeout(std::time::Duration::new(0, 500000000)) {
                Ok((_addr, data)) => (_addr, data),
                Err(_) => continue
            };
            if devices.contains(&_addr.ip()) || data.is_empty() {
                println!("{:?}", &_addr.ip());
                continue
            }

            let data = String::from_utf8_lossy(&data);
            if data.contains("Sonos") {
                devices.insert(_addr.ip());
            }
        }

        devices
    }
}

impl Drop for Discover {
    fn drop(&mut self) {
        // Socket closes on drop automatically, better safe than sorry
        let _ = self.socket.close();
    }
}

impl Default for Discover {
    fn default() -> Self {
        Discover::new()
    }
}
<commit_msg>Add comments<commit_after>extern crate socket;

use socket::{AF_INET, Socket, SOCK_DGRAM, IP_MULTICAST_TTL, IPPROTO_IP};
use std::collections::HashSet;
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::sync::{Arc, mpsc};
use std::thread;
use std::time::Instant;

#[derive(Debug)]
/// `Discover` type
///
/// Used for discovering sonos devices in the local network via the simple service discovery protocol (ssdp).
/// The ssd-protocol works via udp sockets. First a certain search-message is sent to the multicast address (239.255.255.250:1900).
///
/// All answer from upnp (universal plug and play) ready devices are processed and filtered ("Sonos" is in the reply).
pub struct Discover {
    /// Multicast address in the local network
    multicast_addr: SocketAddr,
    /// Socket implementation
    /// INFO: The socket type will likely change in the future due to cross platform compatability
    socket: Arc<Socket>
}

impl Discover {
    pub fn new() -> Self {
        Discover {
            multicast_addr: SocketAddr::from_str("239.255.255.250:1900").unwrap(),
            socket: Discover::create_socket()
        }
    /// Creates a new `Discovery`. Uses the default socket on the default ipv4 multicast address (239.255.255.250:1900).
    ///
    /// # Examples
    ///
    /// ```
    /// use sonos_discovery::Discovery;
    ///
    /// let discovery: Discovery = Discovery::new();
    /// ```
    /// Creates a new `Discovery` with a custom multicast address.
    /// Create a default socket
    /// socket option: AF_INET - SOCK_DGRAM - 0 // Automatically discover the protocol (IPPROTO_UDP)
    /// socket option: IPPROTO_IP - IP_MULTICAST_TTL - 4 // UPnP 1.0 needs a TTL of 4
    }

    fn create_socket() -> Arc<Socket> {
        let socket = Socket::new(AF_INET, SOCK_DGRAM, 0).unwrap();
        let _ = socket.setsockopt(IPPROTO_IP, IP_MULTICAST_TTL, 4);

        Arc::new(socket)
    }

    fn send_search(&self) {
    /// Sends the search message to the defined socket.
    /// Message can't have leading/trailing whitespaces (\s).
    ///
    /// # Message
    /// ```
    /// M-SEARCH * HTTP/1.1
    /// HOST: 239.255.255.250:1900
    /// MAN: "ssdp:discover"
    /// MX: 1
    /// ST: urn:schemas-upnp-org:device:ZonePlayer:1```
        let player_search = r#"M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:schemas-upnp-org:device:ZonePlayer:1"#.as_bytes();
        let _ = self.socket.sendto(player_search, 0, &self.multicast_addr);
    }

    pub fn start(&self, timeout: Option<u32>, device_count: Option<usize>) -> HashSet<IpAddr> {
    /// Start discovering devices.
    ///
    /// # Examples
    /// In this example the search will stop if3 devices have been discovered or the default timeout (5s) is reached.
    /// This is useful if you know the amount of speakers you have and want to reduce the search time.
    ///
    /// ```
    /// use sonos_discovery::Discovery;
    ///
    /// let devices: HashSet<IpAddr> = Discovery::new().start(None, Some(3));
    /// ```
    pub fn start(&self, timeout: Option<u32>, device_count: Option<usize>) -> Result<HashSet<IpAddr>> {
        let timeout = match timeout {
            Some(value) => { value }
            None => 5
        };
        let device_count = match device_count {
            Some(value) => { value }
            None => std::u32::MAX as usize
        };

        let time = Instant::now();

        self.send_search();
        // There's probably a better way than a double clone
        let socket = self.socket.clone();
        let mut devices: HashSet<IpAddr> = HashSet::new();
        while time.elapsed().as_secs() < timeout as u64 && devices.len() < device_count {
            let socket = socket.clone();
            let (sender, receiver) = mpsc::channel();
            let _ = thread::spawn(move ||
                {
                    // TODO: Add logging
                    match socket.recvfrom(1024, 0) {
                        Ok((__addr, _data)) => {
                            let _ = sender.send((__addr, _data));
                            // TODO: Add logging, fail on multiple send errors?
                        }
                        Err(_) => {}
                    }
                }
            );

            // TODO: Add logging, change
            let (_addr, data) = match receiver.recv_timeout(std::time::Duration::new(0, 500000000)) {
                Ok((_addr, data)) => (_addr, data),
                Err(_) => continue
            };

            // Skip from_utf8_lossy
            // Due to the usual small size of `devices`, this is faster than decoding a potentially large response
            if devices.contains(&_addr.ip()) || data.is_empty() {
                println!("{:?}", &_addr.ip());
                continue
            }

            let data = String::from_utf8_lossy(&data);
            if data.contains("Sonos") {
                devices.insert(_addr.ip());
            }
        }

        devices
    }
}

/// Drop internal socket on going out of scope
impl Drop for Discover {
    fn drop(&mut self) {
        // Socket closes on drop automatically, better safe than sorry
        // Log failure for debugging
        let _ = self.socket.close();
    }
}

impl Default for Discover {
    fn default() -> Self {
        Discover::new()
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! Parallel Systems for Entity Components
//! This library provides an ECS variant designed for parallel execution
//! and convenient usage. It is highly flexible when it comes to actual
//! component data and the way it's stored and accessed.

#[macro_use]
extern crate mopa;
extern crate pulse;
extern crate threadpool;
extern crate fnv;

use std::cell::RefCell;
use std::sync::Arc;
use pulse::{Pulse, Signal, Barrier, Signals};
use threadpool::ThreadPool;

pub use storage::{Storage, StorageBase, VecStorage, HashMapStorage};
pub use world::{Component, World, FetchArg,
    EntityBuilder, EntityIter, CreateEntityIter, DynamicEntityIter};

mod storage;
mod world;

/// Index generation. When a new entity is placed at the old index,
/// it bumps the generation by 1. This allows to avoid using components
/// from the entities that were deleted.
/// G<=0 - the entity of generation G is dead
/// G >0 - the entity of generation G is alive
pub type Generation = i32;
/// Index type is arbitrary. It doesn't show up in any interfaces.
/// Keeping it 32bit allows for a single 64bit word per entity.
pub type Index = u32;
/// Entity type, as seen by the user.
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct Entity(Index, Generation);

impl Entity {
    #[cfg(test)]
    /// Create a new entity (externally from ECS)
    pub fn new(index: u32, gen: i32) -> Entity {
        Entity(index, gen)
    }

    /// Get the index of the entity.
    pub fn get_id(&self) -> usize { self.0 as usize }
    /// Get the generation of the entity.
    pub fn get_gen(&self) -> Generation { self.1 }
}

/// System closure run-time argument.
pub struct RunArg {
    world: Arc<World>,
    pulse: RefCell<Option<Pulse>>,
}

impl RunArg {
    /// Borrows the world, allowing the system lock some components and get the entity
    /// iterator. Has to be called only once. Fires a pulse at the end.
    pub fn fetch<'a, U, F>(&'a self, f: F) -> U
        where F: FnOnce(FetchArg<'a>) -> U
    {
        let pulse = self.pulse.borrow_mut().take()
                        .expect("fetch may only be called once.");
        let u = f(FetchArg::new(&self.world));
        pulse.pulse();
        u
    }
    /// Create a new entity dynamically.
    pub fn create(&self) -> Entity {
        self.world.create_later()
    }
    /// Delete an entity dynamically.
    pub fn delete(&self, entity: Entity) {
        self.world.delete_later(entity)
    }
    /// Iterate dynamically added entities.
    pub fn new_entities<'a>(&'a self) -> DynamicEntityIter<'a> {
        self.world.dynamic_entities()
    }
}

/// System execution scheduler. Allows running systems via closures,
/// distributes the load in parallel using a thread pool.
pub struct Scheduler {
    /// Shared World.
    pub world: Arc<World>,
    threads: ThreadPool,
    pending: Vec<Signal>
}

impl Scheduler {
    /// Create a new scheduler, given the world and the thread count.
    pub fn new(world: World, num_threads: usize) -> Scheduler {
        Scheduler {
            world: Arc::new(world),
            threads: ThreadPool::new(num_threads),
            pending: vec![]
        }
    }
    /// Run a custom system.
    pub fn run<F>(&mut self, functor: F) where
        F: 'static + Send + FnOnce(RunArg)
    {
        let (signal, pulse) = Signal::new();
        let (signal_done, pulse_done) = Signal::new();
        let world = self.world.clone();
        self.threads.execute(|| {
            functor(RunArg {
                world: world,
                pulse: RefCell::new(Some(pulse)),
            });
            pulse_done.pulse();
        });
        if signal.wait().is_err() {
            panic!("task panicked before args were captured.")
        }
        self.pending.push(signal_done);
    }
    /// Wait for all the currently executed systems to finish.
    pub fn wait(&mut self) {
        self.world.merge();
        Barrier::new(&self.pending[..]).wait().unwrap();

        for signal in self.pending.drain(..) {
            if signal.wait().is_err() {
                panic!("one or more task as panicked.")
            }
        }
        self.pending.clear();
    }
}

macro_rules! impl_run {
    ($name:ident [$( $write:ident ),*] [$( $read:ident ),*]) => (impl Scheduler {
        #[allow(missing_docs, non_snake_case, unused_mut)]
        pub fn $name<
            $($write:Component,)* $($read:Component,)*
            F: 'static + Send + FnMut( $(&mut $write,)* $(&$read,)* )
        >(&mut self, functor: F) {
            self.run(|run| {
                let mut fun = functor;
                let ($(mut $write,)* $($read,)* entities) = run.fetch(|w|
                    ($(w.write::<$write>(),)*
                     $(w.read::<$read>(),)*
                       w.entities())
                );
                for ent in entities {
                    if let ( $( Some($write), )* $( Some($read), )* ) =
                        ( $( $write.get_mut(ent), )* $( $read.get(ent), )* ) {
                        fun( $($write,)* $($read,)* );
                    }
                }
                for ent in run.new_entities() {
                    if let ( $( Some($write), )* $( Some($read), )* ) =
                        ( $( $write.get_mut(ent), )* $( $read.get(ent), )* ) {
                        fun( $($write,)* $($read,)* );
                    }
                }
            });
        }
    })
}

impl_run!( run0w1r [] [R0] );
impl_run!( run0w2r [] [R0, R1] );
impl_run!( run1w0r [W0] [] );
impl_run!( run1w1r [W0] [R0] );
impl_run!( run1w2r [W0] [R0, R1] );
impl_run!( run1w3r [W0] [R0, R1, R2] );
impl_run!( run1w4r [W0] [R0, R1, R2, R3] );
impl_run!( run1w5r [W0] [R0, R1, R2, R3, R4] );
impl_run!( run1w6r [W0] [R0, R1, R2, R3, R4, R5] );
impl_run!( run1w7r [W0] [R0, R1, R2, R3, R5, R6, R7] );
impl_run!( run2w0r [W0, W1] [] );
impl_run!( run2w1r [W0, W1] [R0] );
impl_run!( run2w2r [W0, W1] [R0, R1] );
<commit_msg>Avoid a deadlock caused by merge winning the lock race with dynamic creation/deletion.<commit_after>#![deny(missing_docs)]

//! Parallel Systems for Entity Components
//! This library provides an ECS variant designed for parallel execution
//! and convenient usage. It is highly flexible when it comes to actual
//! component data and the way it's stored and accessed.

#[macro_use]
extern crate mopa;
extern crate pulse;
extern crate threadpool;
extern crate fnv;

use std::cell::RefCell;
use std::sync::Arc;
use pulse::{Pulse, Signal, Barrier, Signals};
use threadpool::ThreadPool;

pub use storage::{Storage, StorageBase, VecStorage, HashMapStorage};
pub use world::{Component, World, FetchArg,
    EntityBuilder, EntityIter, CreateEntityIter, DynamicEntityIter};

mod storage;
mod world;

/// Index generation. When a new entity is placed at the old index,
/// it bumps the generation by 1. This allows to avoid using components
/// from the entities that were deleted.
/// G<=0 - the entity of generation G is dead
/// G >0 - the entity of generation G is alive
pub type Generation = i32;
/// Index type is arbitrary. It doesn't show up in any interfaces.
/// Keeping it 32bit allows for a single 64bit word per entity.
pub type Index = u32;
/// Entity type, as seen by the user.
#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct Entity(Index, Generation);

impl Entity {
    #[cfg(test)]
    /// Create a new entity (externally from ECS)
    pub fn new(index: u32, gen: i32) -> Entity {
        Entity(index, gen)
    }

    /// Get the index of the entity.
    pub fn get_id(&self) -> usize { self.0 as usize }
    /// Get the generation of the entity.
    pub fn get_gen(&self) -> Generation { self.1 }
}

/// System closure run-time argument.
pub struct RunArg {
    world: Arc<World>,
    pulse: RefCell<Option<Pulse>>,
}

impl RunArg {
    /// Borrows the world, allowing the system lock some components and get the entity
    /// iterator. Has to be called only once. Fires a pulse at the end.
    pub fn fetch<'a, U, F>(&'a self, f: F) -> U
        where F: FnOnce(FetchArg<'a>) -> U
    {
        let pulse = self.pulse.borrow_mut().take()
                        .expect("fetch may only be called once.");
        let u = f(FetchArg::new(&self.world));
        pulse.pulse();
        u
    }
    /// Create a new entity dynamically.
    pub fn create(&self) -> Entity {
        self.world.create_later()
    }
    /// Delete an entity dynamically.
    pub fn delete(&self, entity: Entity) {
        self.world.delete_later(entity)
    }
    /// Iterate dynamically added entities.
    pub fn new_entities<'a>(&'a self) -> DynamicEntityIter<'a> {
        self.world.dynamic_entities()
    }
}

/// System execution scheduler. Allows running systems via closures,
/// distributes the load in parallel using a thread pool.
pub struct Scheduler {
    /// Shared World.
    pub world: Arc<World>,
    threads: ThreadPool,
    pending: Vec<Signal>
}

impl Scheduler {
    /// Create a new scheduler, given the world and the thread count.
    pub fn new(world: World, num_threads: usize) -> Scheduler {
        Scheduler {
            world: Arc::new(world),
            threads: ThreadPool::new(num_threads),
            pending: vec![]
        }
    }
    /// Run a custom system.
    pub fn run<F>(&mut self, functor: F) where
        F: 'static + Send + FnOnce(RunArg)
    {
        let (signal, pulse) = Signal::new();
        let (signal_done, pulse_done) = Signal::new();
        let world = self.world.clone();
        self.threads.execute(|| {
            functor(RunArg {
                world: world,
                pulse: RefCell::new(Some(pulse)),
            });
            pulse_done.pulse();
        });
        if signal.wait().is_err() {
            panic!("task panicked before args were captured.")
        }
        self.pending.push(signal_done);
    }
    /// Wait for all the currently executed systems to finish.
    pub fn wait(&mut self) {
        Barrier::new(&self.pending[..]).wait().unwrap();
        for signal in self.pending.drain(..) {
            if signal.wait().is_err() {
                panic!("one or more task as panicked.")
            }
        }
        self.pending.clear();

        self.world.merge();
    }
}

macro_rules! impl_run {
    ($name:ident [$( $write:ident ),*] [$( $read:ident ),*]) => (impl Scheduler {
        #[allow(missing_docs, non_snake_case, unused_mut)]
        pub fn $name<
            $($write:Component,)* $($read:Component,)*
            F: 'static + Send + FnMut( $(&mut $write,)* $(&$read,)* )
        >(&mut self, functor: F) {
            self.run(|run| {
                let mut fun = functor;
                let ($(mut $write,)* $($read,)* entities) = run.fetch(|w|
                    ($(w.write::<$write>(),)*
                     $(w.read::<$read>(),)*
                       w.entities())
                );
                for ent in entities {
                    if let ( $( Some($write), )* $( Some($read), )* ) =
                        ( $( $write.get_mut(ent), )* $( $read.get(ent), )* ) {
                        fun( $($write,)* $($read,)* );
                    }
                }
                for ent in run.new_entities() {
                    if let ( $( Some($write), )* $( Some($read), )* ) =
                        ( $( $write.get_mut(ent), )* $( $read.get(ent), )* ) {
                        fun( $($write,)* $($read,)* );
                    }
                }
            });
        }
    })
}

impl_run!( run0w1r [] [R0] );
impl_run!( run0w2r [] [R0, R1] );
impl_run!( run1w0r [W0] [] );
impl_run!( run1w1r [W0] [R0] );
impl_run!( run1w2r [W0] [R0, R1] );
impl_run!( run1w3r [W0] [R0, R1, R2] );
impl_run!( run1w4r [W0] [R0, R1, R2, R3] );
impl_run!( run1w5r [W0] [R0, R1, R2, R3, R4] );
impl_run!( run1w6r [W0] [R0, R1, R2, R3, R4, R5] );
impl_run!( run1w7r [W0] [R0, R1, R2, R3, R5, R6, R7] );
impl_run!( run2w0r [W0, W1] [] );
impl_run!( run2w1r [W0, W1] [R0] );
impl_run!( run2w2r [W0, W1] [R0, R1] );
<|endoftext|>


<commit_before>//! Compute dominators of a control-flow graph.
//!
//! # The Dominance Relation
//!
//! In a directed graph with a root node **R**, a node **A** is said to *dominate* a
//! node **B** iff every path from **R** to **B** contains **A**.
//!
//! The node **A** is said to *strictly dominate* the node **B** iff **A** dominates
//! **B** and **A ≠ B**.
//!
//! The node **A** is said to be the *immediate dominator* of a node **B** iff it
//! strictly dominates **B** and there does not exist any node **C** where **A**
//! dominates **C** and **C** dominates **B**.

use std::collections::{HashMap, HashSet};
use std::hash::Hash;

use visit::{DfsPostOrder, GraphBase, IntoNeighbors, Visitable, Walker};

/// The dominance relation for some graph and root.
#[derive(Debug, Clone)]
pub struct Dominators<N>
    where N: Copy + Eq + Hash
{
    root: N,
    dominators: HashMap<N, N>,
}

impl<N> Dominators<N>
    where N: Copy + Eq + Hash
{
    /// Get the root node used to construct these dominance relations.
    pub fn root(&self) -> N {
        self.root
    }

    /// Get the immediate dominator of the given node.
    ///
    /// Returns `None` for any node that is not reachable from the root, and for
    /// the root itself.
    pub fn immediate_dominator(&self, node: N) -> Option<N> {
        if node == self.root {
            None
        } else {
            self.dominators.get(&node).cloned()
        }
    }

    /// Iterate over the given node's that strict dominators.
    ///
    /// If the given node is not reachable from the root, then `None` is
    /// returned.
    pub fn strict_dominators(&self, node: N) -> Option<DominatorsIter<N>> {
        if self.dominators.contains_key(&node) {
            Some(DominatorsIter {
                dominators: self,
                node: self.immediate_dominator(node),
            })
        } else {
            None
        }
    }

    /// Iterate over all of the given node's dominators (including the given
    /// node itself).
    ///
    /// If the given node is not reachable from the root, then `None` is
    /// returned.
    pub fn dominators(&self, node: N) -> Option<DominatorsIter<N>> {
        if self.dominators.contains_key(&node) {
            Some(DominatorsIter {
                dominators: self,
                node: Some(node),
            })
        } else {
            None
        }
    }
}

/// Iterator for a node's dominators.
pub struct DominatorsIter<'a, N>
    where N: 'a + Copy + Eq + Hash
{
    dominators: &'a Dominators<N>,
    node: Option<N>,
}

impl<'a, N> Iterator for DominatorsIter<'a, N>
    where N: 'a + Copy + Eq + Hash
{
    type Item = N;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.node.take();
        if let Some(next) = next {
            self.node = self.dominators.immediate_dominator(next);
        }
        next
    }
}

/// The undefined dominator sentinel, for when we have not yet discovered a
/// node's dominator.
const UNDEFINED: usize = ::std::usize::MAX;

/// This is an implementation of the engineered ["Simple, Fast Dominance
/// Algorithm"][0] discovered by Cooper et al.
///
/// This algorithm is **O(|V|²)**, and therefore has slower theoretical running time
/// than the Lenguaer-Tarjan algorithm (which is **O(|E| log |V|)**. However,
/// Cooper et al found it to be faster in practice on control flow graphs of up
/// to ~30,000 vertices.
///
/// [0]: http://www.cs.rice.edu/~keith/EMBED/dom.pdf
pub fn simple_fast<G>(graph: G, root: G::NodeId) -> Dominators<G::NodeId>
    where G: IntoNeighbors + Visitable,
          <G as GraphBase>::NodeId: Eq + Hash
{
    let (post_order, predecessor_sets) = simple_fast_post_order(graph, root);
    let length = post_order.len();
    debug_assert!(length > 0);
    debug_assert!(post_order.last() == Some(&root));

    // From here on out we use indices into `post_order` instead of actual
    // `NodeId`s wherever possible. This greatly improves the performance of
    // this implementation, but we have to pay a little bit of upfront cost to
    // convert our data structures to play along first.

    // Maps a node to its index into `post_order`.
    let node_to_post_order_idx: HashMap<_, _> = post_order.iter()
        .enumerate()
        .map(|(idx, &node)| (node, idx))
        .collect();

    // Maps a node's `post_order` index to its set of predecessors's indices
    // into `post_order` (as a vec).
    let idx_to_predecessor_vec =
        predecessor_sets_to_idx_vecs(&post_order, &node_to_post_order_idx, predecessor_sets);

    let mut dominators = vec![UNDEFINED; length];
    dominators[length - 1] = length - 1;

    let mut changed = true;
    while changed {
        changed = false;

        // Iterate in reverse post order, skipping the root.

        for idx in (0..length - 1).rev() {
            debug_assert!(post_order[idx] != root);

            // Take the intersection of every predecessor's dominator set; that
            // is the current best guess at the immediate dominator for this
            // node.

            let new_idom_idx = {
                let mut predecessors =
                    idx_to_predecessor_vec[idx].iter().filter(|&&p| dominators[p] != UNDEFINED);
                let new_idom_idx = predecessors.next()
                    .expect("Because the root is initialized to dominate itself, and is the \
                             first node in every path, there must exist a predecessor to this \
                             node that also has a dominator");
                predecessors.fold(*new_idom_idx, |new_idom_idx, &predecessor_idx| {
                    intersect(&dominators, new_idom_idx, predecessor_idx)
                })
            };

            debug_assert!(new_idom_idx < length);

            if new_idom_idx != dominators[idx] {
                dominators[idx] = new_idom_idx;
                changed = true;
            }
        }
    }

    // All done! Translate the indices back into proper `G::NodeId`s.

    debug_assert!(!dominators.iter().any(|&dom| dom == UNDEFINED));

    Dominators {
        root: root,
        dominators: dominators.into_iter()
            .enumerate()
            .map(|(idx, dom_idx)| (post_order[idx], post_order[dom_idx]))
            .collect(),
    }
}

fn intersect(dominators: &[usize], mut finger1: usize, mut finger2: usize) -> usize {
    while finger1 != finger2 {
        if finger1 < finger2 {
            finger1 = dominators[finger1];
        } else if finger2 < finger1 {
            finger2 = dominators[finger2];
        }
    }
    finger1
}

fn predecessor_sets_to_idx_vecs<N>(post_order: &[N],
                                   node_to_post_order_idx: &HashMap<N, usize>,
                                   mut predecessor_sets: HashMap<N, HashSet<N>>)
                                   -> Vec<Vec<usize>>
    where N: Copy + Eq + Hash
{
    post_order.iter()
        .map(|node| {
            predecessor_sets.remove(node)
                .map(|predecessors| {
                    predecessors.into_iter()
                        .map(|p| *node_to_post_order_idx.get(&p).unwrap())
                        .collect()
                })
                .unwrap_or(vec![])
        })
        .collect()
}

fn simple_fast_post_order<G>(graph: G,
                             root: G::NodeId)
                             -> (Vec<G::NodeId>, HashMap<G::NodeId, HashSet<G::NodeId>>)
    where G: IntoNeighbors + Visitable,
          <G as GraphBase>::NodeId: Eq + Hash
{
    let mut post_order = vec![];
    let mut predecessor_sets = HashMap::new();

    for node in DfsPostOrder::new(graph, root).iter(graph) {
        post_order.push(node);

        for successor in graph.neighbors(node) {
            let mut predecessors = predecessor_sets.entry(successor)
                .or_insert_with(HashSet::new);
            predecessors.insert(node);
        }
    }

    (post_order, predecessor_sets)
}

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

    #[test]
    fn test_iter_dominators() {
        let doms: Dominators<u32> = Dominators {
            root: 0,
            dominators: [(2, 1), (1, 0), (0, 0)]
                .iter()
                .cloned()
                .collect(),
        };

        let all_doms: Vec<_> = doms.dominators(2).unwrap().collect();
        assert_eq!(vec![2, 1, 0], all_doms);

        assert_eq!(None, doms.dominators(99).map(|_| unreachable!()));

        let strict_doms: Vec<_> = doms.strict_dominators(2).unwrap().collect();
        assert_eq!(vec![1, 0], strict_doms);

        assert_eq!(None, doms.strict_dominators(99).map(|_| unreachable!()));
    }
}
<commit_msg>Fix future-warning due to comparison with None::<X> with unspecified X<commit_after>//! Compute dominators of a control-flow graph.
//!
//! # The Dominance Relation
//!
//! In a directed graph with a root node **R**, a node **A** is said to *dominate* a
//! node **B** iff every path from **R** to **B** contains **A**.
//!
//! The node **A** is said to *strictly dominate* the node **B** iff **A** dominates
//! **B** and **A ≠ B**.
//!
//! The node **A** is said to be the *immediate dominator* of a node **B** iff it
//! strictly dominates **B** and there does not exist any node **C** where **A**
//! dominates **C** and **C** dominates **B**.

use std::collections::{HashMap, HashSet};
use std::hash::Hash;

use visit::{DfsPostOrder, GraphBase, IntoNeighbors, Visitable, Walker};

/// The dominance relation for some graph and root.
#[derive(Debug, Clone)]
pub struct Dominators<N>
    where N: Copy + Eq + Hash
{
    root: N,
    dominators: HashMap<N, N>,
}

impl<N> Dominators<N>
    where N: Copy + Eq + Hash
{
    /// Get the root node used to construct these dominance relations.
    pub fn root(&self) -> N {
        self.root
    }

    /// Get the immediate dominator of the given node.
    ///
    /// Returns `None` for any node that is not reachable from the root, and for
    /// the root itself.
    pub fn immediate_dominator(&self, node: N) -> Option<N> {
        if node == self.root {
            None
        } else {
            self.dominators.get(&node).cloned()
        }
    }

    /// Iterate over the given node's that strict dominators.
    ///
    /// If the given node is not reachable from the root, then `None` is
    /// returned.
    pub fn strict_dominators(&self, node: N) -> Option<DominatorsIter<N>> {
        if self.dominators.contains_key(&node) {
            Some(DominatorsIter {
                dominators: self,
                node: self.immediate_dominator(node),
            })
        } else {
            None
        }
    }

    /// Iterate over all of the given node's dominators (including the given
    /// node itself).
    ///
    /// If the given node is not reachable from the root, then `None` is
    /// returned.
    pub fn dominators(&self, node: N) -> Option<DominatorsIter<N>> {
        if self.dominators.contains_key(&node) {
            Some(DominatorsIter {
                dominators: self,
                node: Some(node),
            })
        } else {
            None
        }
    }
}

/// Iterator for a node's dominators.
pub struct DominatorsIter<'a, N>
    where N: 'a + Copy + Eq + Hash
{
    dominators: &'a Dominators<N>,
    node: Option<N>,
}

impl<'a, N> Iterator for DominatorsIter<'a, N>
    where N: 'a + Copy + Eq + Hash
{
    type Item = N;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.node.take();
        if let Some(next) = next {
            self.node = self.dominators.immediate_dominator(next);
        }
        next
    }
}

/// The undefined dominator sentinel, for when we have not yet discovered a
/// node's dominator.
const UNDEFINED: usize = ::std::usize::MAX;

/// This is an implementation of the engineered ["Simple, Fast Dominance
/// Algorithm"][0] discovered by Cooper et al.
///
/// This algorithm is **O(|V|²)**, and therefore has slower theoretical running time
/// than the Lenguaer-Tarjan algorithm (which is **O(|E| log |V|)**. However,
/// Cooper et al found it to be faster in practice on control flow graphs of up
/// to ~30,000 vertices.
///
/// [0]: http://www.cs.rice.edu/~keith/EMBED/dom.pdf
pub fn simple_fast<G>(graph: G, root: G::NodeId) -> Dominators<G::NodeId>
    where G: IntoNeighbors + Visitable,
          <G as GraphBase>::NodeId: Eq + Hash
{
    let (post_order, predecessor_sets) = simple_fast_post_order(graph, root);
    let length = post_order.len();
    debug_assert!(length > 0);
    debug_assert!(post_order.last() == Some(&root));

    // From here on out we use indices into `post_order` instead of actual
    // `NodeId`s wherever possible. This greatly improves the performance of
    // this implementation, but we have to pay a little bit of upfront cost to
    // convert our data structures to play along first.

    // Maps a node to its index into `post_order`.
    let node_to_post_order_idx: HashMap<_, _> = post_order.iter()
        .enumerate()
        .map(|(idx, &node)| (node, idx))
        .collect();

    // Maps a node's `post_order` index to its set of predecessors's indices
    // into `post_order` (as a vec).
    let idx_to_predecessor_vec =
        predecessor_sets_to_idx_vecs(&post_order, &node_to_post_order_idx, predecessor_sets);

    let mut dominators = vec![UNDEFINED; length];
    dominators[length - 1] = length - 1;

    let mut changed = true;
    while changed {
        changed = false;

        // Iterate in reverse post order, skipping the root.

        for idx in (0..length - 1).rev() {
            debug_assert!(post_order[idx] != root);

            // Take the intersection of every predecessor's dominator set; that
            // is the current best guess at the immediate dominator for this
            // node.

            let new_idom_idx = {
                let mut predecessors =
                    idx_to_predecessor_vec[idx].iter().filter(|&&p| dominators[p] != UNDEFINED);
                let new_idom_idx = predecessors.next()
                    .expect("Because the root is initialized to dominate itself, and is the \
                             first node in every path, there must exist a predecessor to this \
                             node that also has a dominator");
                predecessors.fold(*new_idom_idx, |new_idom_idx, &predecessor_idx| {
                    intersect(&dominators, new_idom_idx, predecessor_idx)
                })
            };

            debug_assert!(new_idom_idx < length);

            if new_idom_idx != dominators[idx] {
                dominators[idx] = new_idom_idx;
                changed = true;
            }
        }
    }

    // All done! Translate the indices back into proper `G::NodeId`s.

    debug_assert!(!dominators.iter().any(|&dom| dom == UNDEFINED));

    Dominators {
        root: root,
        dominators: dominators.into_iter()
            .enumerate()
            .map(|(idx, dom_idx)| (post_order[idx], post_order[dom_idx]))
            .collect(),
    }
}

fn intersect(dominators: &[usize], mut finger1: usize, mut finger2: usize) -> usize {
    while finger1 != finger2 {
        if finger1 < finger2 {
            finger1 = dominators[finger1];
        } else if finger2 < finger1 {
            finger2 = dominators[finger2];
        }
    }
    finger1
}

fn predecessor_sets_to_idx_vecs<N>(post_order: &[N],
                                   node_to_post_order_idx: &HashMap<N, usize>,
                                   mut predecessor_sets: HashMap<N, HashSet<N>>)
                                   -> Vec<Vec<usize>>
    where N: Copy + Eq + Hash
{
    post_order.iter()
        .map(|node| {
            predecessor_sets.remove(node)
                .map(|predecessors| {
                    predecessors.into_iter()
                        .map(|p| *node_to_post_order_idx.get(&p).unwrap())
                        .collect()
                })
                .unwrap_or(vec![])
        })
        .collect()
}

fn simple_fast_post_order<G>(graph: G,
                             root: G::NodeId)
                             -> (Vec<G::NodeId>, HashMap<G::NodeId, HashSet<G::NodeId>>)
    where G: IntoNeighbors + Visitable,
          <G as GraphBase>::NodeId: Eq + Hash
{
    let mut post_order = vec![];
    let mut predecessor_sets = HashMap::new();

    for node in DfsPostOrder::new(graph, root).iter(graph) {
        post_order.push(node);

        for successor in graph.neighbors(node) {
            let mut predecessors = predecessor_sets.entry(successor)
                .or_insert_with(HashSet::new);
            predecessors.insert(node);
        }
    }

    (post_order, predecessor_sets)
}

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

    #[test]
    fn test_iter_dominators() {
        let doms: Dominators<u32> = Dominators {
            root: 0,
            dominators: [(2, 1), (1, 0), (0, 0)]
                .iter()
                .cloned()
                .collect(),
        };

        let all_doms: Vec<_> = doms.dominators(2).unwrap().collect();
        assert_eq!(vec![2, 1, 0], all_doms);

        assert_eq!(None::<()>, doms.dominators(99).map(|_| unreachable!()));

        let strict_doms: Vec<_> = doms.strict_dominators(2).unwrap().collect();
        assert_eq!(vec![1, 0], strict_doms);

        assert_eq!(None::<()>, doms.strict_dominators(99).map(|_| unreachable!()));
    }
}
<|endoftext|>


<commit_before>use clap::ArgMatches;
use enr::Enr;
use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder};
use serde_derive::{Deserialize, Serialize};
use std::path::PathBuf;
use std::time::Duration;

/// The beacon node topic string to subscribe to.
pub const BEACON_PUBSUB_TOPIC: &str = "beacon_block";
pub const BEACON_ATTESTATION_TOPIC: &str = "beacon_attestation";
//TODO: Implement shard subnets
pub const SHARD_TOPIC_PREFIX: &str = "shard";

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
/// Network configuration for lighthouse.
pub struct Config {
    /// Data directory where node's keyfile is stored
    pub network_dir: PathBuf,

    /// IP address to listen on.
    pub listen_address: std::net::IpAddr,

    /// The TCP port that libp2p listens on.
    pub libp2p_port: u16,

    /// The address to broadcast to peers about which address we are listening on.
    pub discovery_address: std::net::IpAddr,

    /// UDP port that discovery listens on.
    pub discovery_port: u16,

    /// Target number of connected peers.
    pub max_peers: usize,

    /// Gossipsub configuration parameters.
    #[serde(skip)]
    pub gs_config: GossipsubConfig,

    /// List of nodes to initially connect to.
    pub boot_nodes: Vec<Enr>,

    /// Client version
    pub client_version: String,

    /// List of extra topics to initially subscribe to as strings.
    pub topics: Vec<String>,
}

impl Default for Config {
    /// Generate a default network configuration.
    fn default() -> Self {
        let mut network_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
        network_dir.push(".lighthouse");
        network_dir.push("network");
        Config {
            network_dir,
            listen_address: "127.0.0.1".parse().expect("vaild ip address"),
            libp2p_port: 9000,
            discovery_address: "127.0.0.1".parse().expect("valid ip address"),
            discovery_port: 9000,
            max_peers: 10,
            //TODO: Set realistic values for production
            gs_config: GossipsubConfigBuilder::new()
                .max_gossip_size(4_000_000)
                .inactivity_timeout(Duration::from_secs(90))
                .heartbeat_interval(Duration::from_secs(20))
                .build(),
            boot_nodes: vec![],
            client_version: version::version(),
            topics: Vec::new(),
        }
    }
}

/// Generates a default Config.
impl Config {
    pub fn new() -> Self {
        Config::default()
    }

    pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), String> {
        if let Some(dir) = args.value_of("datadir") {
            self.network_dir = PathBuf::from(dir).join("network");
        };

        if let Some(listen_address_str) = args.value_of("listen-address") {
            let listen_address = listen_address_str
                .parse()
                .map_err(|_| format!("Invalid listen address: {:?}", listen_address_str))?;
            self.listen_address = listen_address;
            self.discovery_address = listen_address;
        }

        if let Some(max_peers_str) = args.value_of("maxpeers") {
            self.max_peers = max_peers_str
                .parse::<usize>()
                .map_err(|_| format!("Invalid number of max peers: {}", max_peers_str))?;
        }

        if let Some(port_str) = args.value_of("port") {
            let port = port_str
                .parse::<u16>()
                .map_err(|_| format!("Invalid port: {}", port_str))?;
            self.libp2p_port = port;
            self.discovery_port = port;
        }

        if let Some(boot_enr_str) = args.value_of("boot-nodes") {
            self.boot_nodes = boot_enr_str
                .split(',')
                .map(|enr| enr.parse().map_err(|_| format!("Invalid ENR: {}", enr)))
                .collect::<Result<Vec<Enr>, _>>()?;
        }

        if let Some(discovery_address_str) = args.value_of("discovery-address") {
            self.discovery_address = discovery_address_str
                .parse()
                .map_err(|_| format!("Invalid discovery address: {:?}", discovery_address_str))?
        }

        if let Some(disc_port_str) = args.value_of("disc-port") {
            self.discovery_port = disc_port_str
                .parse::<u16>()
                .map_err(|_| format!("Invalid discovery port: {}", disc_port_str))?;
        }

        Ok(())
    }
}
<commit_msg>Remove Phase 1 TODO<commit_after>use clap::ArgMatches;
use enr::Enr;
use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder};
use serde_derive::{Deserialize, Serialize};
use std::path::PathBuf;
use std::time::Duration;

/// The beacon node topic string to subscribe to.
pub const BEACON_PUBSUB_TOPIC: &str = "beacon_block";
pub const BEACON_ATTESTATION_TOPIC: &str = "beacon_attestation";
pub const SHARD_TOPIC_PREFIX: &str = "shard";

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
/// Network configuration for lighthouse.
pub struct Config {
    /// Data directory where node's keyfile is stored
    pub network_dir: PathBuf,

    /// IP address to listen on.
    pub listen_address: std::net::IpAddr,

    /// The TCP port that libp2p listens on.
    pub libp2p_port: u16,

    /// The address to broadcast to peers about which address we are listening on.
    pub discovery_address: std::net::IpAddr,

    /// UDP port that discovery listens on.
    pub discovery_port: u16,

    /// Target number of connected peers.
    pub max_peers: usize,

    /// Gossipsub configuration parameters.
    #[serde(skip)]
    pub gs_config: GossipsubConfig,

    /// List of nodes to initially connect to.
    pub boot_nodes: Vec<Enr>,

    /// Client version
    pub client_version: String,

    /// List of extra topics to initially subscribe to as strings.
    pub topics: Vec<String>,
}

impl Default for Config {
    /// Generate a default network configuration.
    fn default() -> Self {
        let mut network_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
        network_dir.push(".lighthouse");
        network_dir.push("network");
        Config {
            network_dir,
            listen_address: "127.0.0.1".parse().expect("vaild ip address"),
            libp2p_port: 9000,
            discovery_address: "127.0.0.1".parse().expect("valid ip address"),
            discovery_port: 9000,
            max_peers: 10,
            //TODO: Set realistic values for production
            gs_config: GossipsubConfigBuilder::new()
                .max_gossip_size(4_000_000)
                .inactivity_timeout(Duration::from_secs(90))
                .heartbeat_interval(Duration::from_secs(20))
                .build(),
            boot_nodes: vec![],
            client_version: version::version(),
            topics: Vec::new(),
        }
    }
}

/// Generates a default Config.
impl Config {
    pub fn new() -> Self {
        Config::default()
    }

    pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), String> {
        if let Some(dir) = args.value_of("datadir") {
            self.network_dir = PathBuf::from(dir).join("network");
        };

        if let Some(listen_address_str) = args.value_of("listen-address") {
            let listen_address = listen_address_str
                .parse()
                .map_err(|_| format!("Invalid listen address: {:?}", listen_address_str))?;
            self.listen_address = listen_address;
            self.discovery_address = listen_address;
        }

        if let Some(max_peers_str) = args.value_of("maxpeers") {
            self.max_peers = max_peers_str
                .parse::<usize>()
                .map_err(|_| format!("Invalid number of max peers: {}", max_peers_str))?;
        }

        if let Some(port_str) = args.value_of("port") {
            let port = port_str
                .parse::<u16>()
                .map_err(|_| format!("Invalid port: {}", port_str))?;
            self.libp2p_port = port;
            self.discovery_port = port;
        }

        if let Some(boot_enr_str) = args.value_of("boot-nodes") {
            self.boot_nodes = boot_enr_str
                .split(',')
                .map(|enr| enr.parse().map_err(|_| format!("Invalid ENR: {}", enr)))
                .collect::<Result<Vec<Enr>, _>>()?;
        }

        if let Some(discovery_address_str) = args.value_of("discovery-address") {
            self.discovery_address = discovery_address_str
                .parse()
                .map_err(|_| format!("Invalid discovery address: {:?}", discovery_address_str))?
        }

        if let Some(disc_port_str) = args.value_of("disc-port") {
            self.discovery_port = disc_port_str
                .parse::<u16>()
                .map_err(|_| format!("Invalid discovery port: {}", disc_port_str))?;
        }

        Ok(())
    }
}
<|endoftext|>