<commit_before>use ::board;
use ::game;

use ::actions::Action;

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::clone::Clone;
use std::default::Default;
use std::ops::RangeFrom;

#[derive(Clone, Debug, Eq, PartialEq)]
struct ActionId(usize);

impl ActionId {
    fn as_usize(self) -> usize {
        let ActionId(value) = self;
        value
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct StateId(usize);

impl StateId {
    fn as_usize(self) -> usize {
        let StateId(value) = self;
        value
    }
}

struct StateNamespace {
    state_id_generator: RangeFrom<usize>,
    states: HashMap<game::State, StateId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum NamespaceInsertion {
    Present(StateId),
    New(StateId),
}

impl NamespaceInsertion {
    fn unwrap(self) -> StateId {
        match self {
            NamespaceInsertion::Present(s) => s,
            NamespaceInsertion::New(s) => s,
        }
    }
}

impl StateNamespace {
    fn new() -> Self {
        StateNamespace {
            state_id_generator: 0..,
            states: HashMap::new(),
        }
    }

    fn next_id(&mut self) -> StateId {
        match self.state_id_generator.next() {
            Some(id) => StateId(id),
            None => panic!("Exhausted state ID namespace"),
        }
    }

    fn get_or_insert(&mut self, state: game::State) -> NamespaceInsertion {
        match self.states.entry(state) {
            Entry::Occupied(e) => NamespaceInsertion::Present(*e.get()),
            Entry::Vacant(e) => NamespaceInsertion::New(*e.insert(self.next_id())),
        }
    }

    fn get(&self, state: &game::State) -> Option<StateId> {
        self.states.get(state).map(|x| *x)
    }
}

struct ActionNamespace {
    action_id_generator: RangeFrom<usize>,
}

impl ActionNamespace {
    fn new() -> Self {
        ActionNamespace {
            action_id_generator: 0..,
        }
    }

    fn next_id(&mut self) -> ActionId {
        match self.action_id_generator.next() {
            Some(id) => ActionId(id),
            None => panic!("Exhausted action ID namespace"),
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum ActionTarget {
    Unexpanded,
    Cycle,
    State(StateId),
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
struct ActionArc {
    action: Action,
    source: StateId,
    target: ActionTarget,
}

pub struct SearchGraph<S, A> where S: Default, A: Default {
    root_id: StateId,
    state_ids: StateNamespace,
    action_ids: ActionNamespace,
    // Also consider making edges into an intrusive linked list, with head an
    // Option<EdgeNode> and EdgeNode<A> { data: A, action: Action, target:
    // StateId, next: Option<EdgeNode> }.
    state_out_edges: Vec<Vec<ActionId>>,  // Indexed by StateId.
    state_in_edges: Vec<Vec<ActionId>>,  // Indexed by StateId.
    action_arcs: Vec<ActionArc>,  // Indexed by ActionId.
    state_data: Vec<S>,  // Indexed by StateId.
    action_data: Vec<A>,  // Indexed by ActionId.
}

impl<S, A> SearchGraph<S, A> where S: Default, A: Default {
    pub fn new(root_state: game::State) -> Self {
        let mut graph = SearchGraph {
            root_id: StateId(0),
            state_ids: StateNamespace::new(),
            action_ids: ActionNamespace::new(),
            state_out_edges: Vec::new(),
            state_in_edges: Vec::new(),
            action_arcs: Vec::new(),
            state_data: Vec::new(),
            action_data: Vec::new(),
        };
        graph.add_state(root_state);
        graph
    }

    fn add_state(&mut self, state: game::State) -> NamespaceInsertion {
        match self.state_ids.get_or_insert(state) {
            (state, NamespaceInsertion::New(state_id)) => {
                self.state_data.push(Default::default());
                self.state_out_edges.push(Vec::new());
                self.state_in_edges.push(Vec::new());
                for action in state.role_actions(state.active_player().role()) {
                    self.add_action_arc(action, state_id, ActionTarget::Unexpanded);
                }
                assert!(self.state_data.len() == state_id.as_usize() + 1);
                assert!(self.state_out_edges.len() == state_id.as_usize() + 1);
                assert!(self.state_in_edges.len() == state_id.as_usize() + 1);
                NamespaceInsertion::New(state_id)
            },
            (_, insertion) => insertion,
        }
    }

    fn add_action_arc(&mut self, action: Action, source: StateId, target: ActionTarget) {
        let arc = ActionArc { action: action, source: source, target: target, };
        let action_id = self.action_ids.next_id();
        self.state_out_edges[source.as_usize()].push(action_id);
        self.action_arcs.push(arc);
        self.action_data.push(Default::default());
        assert!(self.action_arcs.len() == action_id.as_usize() + 1);
        assert!(self.action_data.len() == action_id.as_usize() + 1);
    }

    fn expand_action_target(&mut self, from_state: &game::State, id: ActionId) {
        let arc: &mut ActionArc = &mut self.action_arcs[id.as_usize()];
        match arc.target {
            ActionTarget::Unexpanded => {
                match self.state_ids.states.get(from_state) {
                    Some(source_id) => {
                        if *source_id != arc.source {
                            panic!("Source state ID {:?} does not match action source {:?}",
                                   source_id, arc.source);
                        }
                        let mut target_state = from_state.clone();
                        target_state.do_action(&arc.action);
                        match self.add_state(target_state) {
                            NamespaceInsertion::New(target_id) =>
                                self.state_in_edges[target_id.as_usize()].push(id),
                            NamespaceInsertion::Present(target_id) => {
                                if self.path_exists(target_id, *source_id) {
                                    arc.target = ActionTarget::Cycle;
                                } else {
                                    arc.target = ActionTarget::State(target_id);
                                }
                            },
                        }
                    },
                    None =>
                        panic!("Source state supplied for action {:?} does not match known states",
                               arc),
                }
            },
            _ => panic!("Action {:?} already expanded", arc),
        }
    }

    fn path_exists(self, source: StateId, target: StateId) -> bool {
        let mut frontier = vec![target];
        while !frontier.is_empty() {
            let state = frontier.pop().unwrap();
            if source == state {
                return true
            }
            for arc in self.state_out_edges[state.as_usize()].iter().map(|&x| &self.action_arcs[x.as_usize()]) {
                if let ActionTarget::State(target_id) = arc.target {
                    frontier.push(target_id);
                }
            }
        }
        false
    }

    // pub fn get_state<'s>(&'s mut self, states: game::State) -> StateNode<'s, S, A> {

    // }
}

pub struct StateNode<'a, S: 'a, A: 'a> where S: Default, A: Default {
    graph: &'a mut SearchGraph<S, A>,
    id: StateId,
}

impl<'a, S: 'a, A: 'a> StateNode<'a, S, A> where S: Default, A: Default {
    fn child_actions(&self) -> &[ActionId] {
        &self.graph.state_out_edges[self.id.as_usize()]
    }

    fn parent_actions(&self) -> &[ActionId] {
        &self.graph.state_in_edges[self.id.as_usize()]
    }

    pub fn data(&self) -> &S {
        &self.graph.state_data[self.id.as_usize()]
    }
}
<commit_msg>Major progress in game search DAG, modulo passing game state when traversing.<commit_after>use ::game;

use ::actions::Action;

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::clone::Clone;
use std::default::Default;
use std::ops::RangeFrom;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct ArcId(usize);

impl ArcId {
    fn as_usize(self) -> usize {
        let ArcId(value) = self;
        value
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct StateId(usize);

impl StateId {
    fn as_usize(self) -> usize {
        let StateId(value) = self;
        value
    }
}

struct StateNamespace {
    states: HashMap<game::State, StateId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum NamespaceInsertion {
    Present(StateId),
    New(StateId),
}

impl StateNamespace {
    fn new() -> Self {
        StateNamespace {
            states: HashMap::new(),
        }
    }

    fn get_or_insert(&mut self, state: game::State) -> NamespaceInsertion {
        let next_state_id = StateId(self.states.len());
        match self.states.entry(state) {
            Entry::Occupied(e) => NamespaceInsertion::Present(*e.get()),
            Entry::Vacant(e) => NamespaceInsertion::New(*e.insert(next_state_id)),
        }
    }

    fn get(&self, state: &game::State) -> Option<StateId> {
        self.states.get(state).map(|x| *x)
    }
}

struct ArcNamespace {
    arc_id_generator: RangeFrom<usize>,
}

impl ArcNamespace {
    fn new() -> Self {
        ArcNamespace {
            arc_id_generator: 0..,
        }
    }

    fn next_id(&mut self) -> ArcId {
        match self.arc_id_generator.next() {
            Some(id) => ArcId(id),
            None => panic!("Exhausted arc ID namespace"),
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum ActionTarget {
    Unexpanded,
    Cycle,
    State(StateId),
}

impl ActionTarget {
    fn unwrap(self) -> StateId {
        match self {
            ActionTarget::State(id) => id,
            _ => panic!("Can't unwrap {:?}", self),
        }
    }

    fn to_option(self) -> Option<StateId> {
        match self {
            ActionTarget::State(id) => Some(id),
            _ => None,
        }
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
struct Arc {
    action: Action,
    source: StateId,
    target: ActionTarget,
}

pub struct SearchGraph<S, A> where S: Default, A: Default {
    root_id: StateId,
    state_ids: StateNamespace,
    arc_ids: ArcNamespace,
    state_out: Vec<Vec<ArcId>>,  // Indexed by StateId.
    state_in: Vec<Vec<ArcId>>,  // Indexed by StateId.
    state_data: Vec<S>,  // Indexed by StateId.
    arcs: Vec<Arc>,  // Indexed by ArcId.
    arc_data: Vec<A>,  // Indexed by ArcId.
}

impl<S, A> SearchGraph<S, A> where S: Default, A: Default {
    pub fn new(root_state: &game::State) -> Self {
        let mut graph = SearchGraph {
            root_id: StateId(0),
            state_ids: StateNamespace::new(),
            arc_ids: ArcNamespace::new(),
            state_out: Vec::new(),
            state_in: Vec::new(),
            arcs: Vec::new(),
            state_data: Vec::new(),
            arc_data: Vec::new(),
        };
        graph.add_state(&root_state);
        graph
    }

    fn add_state(&mut self, state: &game::State) -> NamespaceInsertion {
        let actions = state.role_actions(state.active_player().role());
        match self.state_ids.get_or_insert(state.clone()) {
            NamespaceInsertion::New(state_id) => {
                self.state_data.push(Default::default());
                self.state_out.push(Vec::new());
                self.state_in.push(Vec::new());
                for action in actions {
                    self.add_arc(action, state_id, ActionTarget::Unexpanded);
                }
                assert!(self.state_data.len() == state_id.as_usize() + 1);
                assert!(self.state_out.len() == state_id.as_usize() + 1);
                assert!(self.state_in.len() == state_id.as_usize() + 1);
                NamespaceInsertion::New(state_id)
            },
            x @ _ => x,
        }
    }

    fn add_arc(&mut self, action: Action, source: StateId, target: ActionTarget) {
        let arc = Arc { action: action, source: source, target: target, };
        let arc_id = self.arc_ids.next_id();
        if let ActionTarget::State(target_id) = target {
            self.state_in[target_id.as_usize()].push(arc_id);
        }
        self.state_out[source.as_usize()].push(arc_id);
        self.arcs.push(arc);
        self.arc_data.push(Default::default());
        assert!(self.arcs.len() == arc_id.as_usize() + 1);
        assert!(self.arc_data.len() == arc_id.as_usize() + 1);
    }

    fn expand_action_target(&mut self, from_state: &game::State, id: ArcId) -> Option<StateId> {
        let (arc_source, arc_target) = {
            let arc = &self.arcs[id.as_usize()];
            (arc.source, arc.target)
        };
        let new_target = match arc_target {
            ActionTarget::Unexpanded => {
                match self.state_ids.states.get(from_state).map(|x| *x) {
                    Some(source_id) => {
                        if source_id != arc_source {
                            panic!("Source state ID {:?} does not match action source {:?}",
                                   source_id, arc_source);
                        }
                        let mut target_state = from_state.clone();
                        target_state.do_action(&self.arcs[id.as_usize()].action);
                        match self.add_state(&target_state) {
                            NamespaceInsertion::New(target_id) => {
                                self.state_in[target_id.as_usize()].push(id);
                                ActionTarget::State(target_id)
                            },
                            NamespaceInsertion::Present(target_id) => {
                                if self.path_exists(target_id, source_id) {
                                    ActionTarget::Cycle
                                } else {
                                    ActionTarget::State(target_id)
                                }
                            },
                        }
                    },
                    None =>
                        panic!("Source state supplied for action {:?} does not match known states",
                               self.arcs[id.as_usize()]),
                }
            },
            _ => panic!("Action {:?} already expanded", self.arcs[id.as_usize()]),
        };
        self.arcs[id.as_usize()].target = new_target;
    }

    fn path_exists(&self, source: StateId, target: StateId) -> bool {
        let mut frontier = vec![target];
        while !frontier.is_empty() {
            let state = frontier.pop().unwrap();
            if source == state {
                return true
            }
            for arc in self.state_out[state.as_usize()].iter().map(|&x| &self.arcs[x.as_usize()]) {
                if let ActionTarget::State(target_id) = arc.target {
                    frontier.push(target_id);
                }
            }
        }
        false
    }

    pub fn get_node<'s>(&'s self, state: &game::State) -> Option<Node<'s, S, A>> {
        match self.state_ids.get(state) {
            Some(id) => Some(Node { graph: self, state: state.clone(), id: id, }),
            None => None,
        }
    }

    pub fn get_node_mut<'s>(&'s mut self, state: &game::State) -> Option<MutNode<'s, S, A>> {
        match self.state_ids.get(state) {
            Some(id) => Some(MutNode { graph: self, state: state.clone(), id: id, }),
            None => None,
        }
    }

    pub fn promote_node_mut<'s>(&'s mut self, node: Node<'s, S, A>) -> MutNode<'s, S, A> {
        MutNode { graph: self, state: node.state, id: node.id, }
    }
}

pub struct Node<'a, S, A> where S: Default + 'a, A: Default + 'a {
    graph: &'a SearchGraph<S, A>,
    state: game::State,
    id: StateId,
}

impl<'a, S, A> Node<'a, S, A> where S: Default + 'a, A: Default + 'a {
    fn child_actions(&self) -> &'a [ArcId] {
        &self.graph.state_out[self.id.as_usize()]
    }

    fn parent_actions(&self) -> &'a [ArcId] {
        &self.graph.state_in[self.id.as_usize()]
    }

    pub fn data(&self) -> &'a S {
        &self.graph.state_data[self.id.as_usize()]
    }

    pub fn out_edges(&self) -> OutEdgeList<'a, S, A> {
        OutEdgeList { graph: self.graph, state: self.state, children: self.child_actions(), }
    }

    pub fn in_edges(&self) -> InEdgeList<'a, S, A> {
        InEdgeList { graph: self.graph, state: self.state, parents: self.parent_actions(), }
    }
}

pub enum OutEdge<'a, S, A> where S: Default + 'a, A: Default + 'a {
    Cycle,
    Unexpanded,
    Expanded(ExpandedData<'a, S, A>),
}

pub struct ExpandedData<'a, S, A> where S: Default + 'a, A: Default + 'a {
    graph: &'a SearchGraph<S, A>,
    state: game::State,
    id: ArcId,
}

impl<'a, S, A> ExpandedData<'a, S, A> where S: Default + 'a, A: Default + 'a {
    fn arc(&self) -> &'a Arc {
        &self.graph.arcs[self.id.as_usize()]
    }

    pub fn action(&self) -> &'a Action {
        &self.arc().action
    }

    pub fn source(&self) -> Node<'a, S, A> {
        Node { graph: self.graph, state: self.state, id: self.arc().source, }
    }

    pub fn target(&self) -> Node<'a, S, A> {
        let mut target_state = self.state.clone();
        target_state.do_action(self.action());
        Node { graph: self.graph, state: target_state, id: self.arc().target.unwrap(), }
    }

    pub fn data(&self) -> &'a A {
        &self.graph.arc_data[self.id.as_usize()]
    }
}

pub struct OutEdgeList<'a, S, A> where S: Default + 'a, A: Default + 'a {
    graph: &'a SearchGraph<S, A>,
    state: game::State,
    children: &'a [ArcId],
}

impl<'a, S, A> OutEdgeList<'a, S, A> where S: Default + 'a, A: Default + 'a {
    pub fn is_empty(&self) -> bool {
        self.children.is_empty()
    }

    pub fn len(&self) -> usize {
        self.children.len()
    }

    pub fn get(&self, i: usize) -> OutEdge<'a, S, A> {
        match self.graph.arcs[self.children[i].as_usize()].target {
            ActionTarget::Unexpanded => OutEdge::Unexpanded,
            ActionTarget::Cycle => OutEdge::Cycle,
            ActionTarget::State(_) =>
                OutEdge::Expanded(ExpandedData { graph: self.graph, state: self.state, id: self.children[i], }),
        }
    }
}

pub struct InEdgeList<'a, S, A> where S: Default + 'a, A: Default + 'a {
    graph: &'a SearchGraph<S, A>,
    state: game::State,
    parents: &'a [ArcId],
}

impl<'a, S, A> InEdgeList<'a, S, A> where S: Default + 'a, A: Default + 'a {
    pub fn is_empty(&self) -> bool {
        self.parents.is_empty()
    }

    pub fn len(&self) -> usize {
        self.parents.len()
    }

    pub fn get(&self, i: usize) -> ExpandedData<'a, S, A> {
        let mut parent_state = self.state.clone();
        ExpandedData { graph: self.graph, state: self.state, id: self.parents[i], }
    }
}

pub struct MutNode<'a, S, A> where S: Default + 'a, A: Default + 'a {
    graph: &'a mut SearchGraph<S, A>,
    state: game::State,
    id: StateId,
}

impl<'a, S, A> MutNode<'a, S, A> where S: Default + 'a, A: Default + 'a {
    fn child_actions(&self) -> &[ArcId] {
        &self.graph.state_out[self.id.as_usize()]
    }

    fn parent_actions(&self) -> &[ArcId] {
        &self.graph.state_in[self.id.as_usize()]
    }

    pub fn data(&self) -> &S {
        &self.graph.state_data[self.id.as_usize()]
    }

    pub fn data_mut(&mut self) -> &mut S {
        &mut self.graph.state_data[self.id.as_usize()]
    }

    pub fn out_edges<'s>(&'s self) -> OutEdgeList<'s, S, A> {
        OutEdgeList { graph: self.graph, state: self.state, children: self.child_actions(), }
    }

    pub fn out_edges_mut(mut self) -> MutOutEdgeList<'a, S, A> {
        MutOutEdgeList { graph: self.graph, state: self.state, source_id: self.id, }
    }

    pub fn in_edges<'s>(&'s self) -> InEdgeList<'s, S, A> {
        InEdgeList { graph: self.graph, parents: self.parent_actions(), }
    }

    pub fn in_edges_mut(mut self) -> MutInEdgeList<'a, S, A> {
        MutInEdgeList { graph: self.graph, target_id: self.id, }
    }
}

pub struct MutOutEdgeList<'a, S, A> where S: Default + 'a, A: Default + 'a {
    graph: &'a mut SearchGraph<S, A>,
    state: game::State,
    source_id: StateId,
}

impl<'a, S, A> MutOutEdgeList<'a, S, A> where S: Default + 'a, A: Default + 'a {
    pub fn is_empty(&self) -> bool {
        self.graph.state_out[self.source_id.as_usize()].is_empty()
    }

    pub fn len(&self) -> usize {
        self.graph.state_out[self.source_id.as_usize()].len()
    }

    pub fn get<'s>(&'s self, i: usize) -> OutEdge<'s, S, A> {
        match self.graph.arcs[self.graph.state_out[self.source_id.as_usize()][i].as_usize()].target {
            ActionTarget::Unexpanded => OutEdge::Unexpanded,
            ActionTarget::Cycle => OutEdge::Cycle,
            ActionTarget::State(_) =>
                OutEdge::Expanded(ExpandedData { graph: self.graph, id: self.graph.state_out[self.source_id.as_usize()][i], }),
        }
    }

    pub fn get_mut(self, i: usize) -> MutOutEdge<'a, S, A> {
        match self.graph.arcs[self.graph.state_out[self.source_id.as_usize()][i].as_usize()].target {
            ActionTarget::Unexpanded => {
                let id = self.graph.state_out[self.source_id.as_usize()][i];
                MutOutEdge::Unexpanded(MutUnexpandedData { graph: self.graph, state: self.state, id: id, })
            },
            ActionTarget::Cycle => MutOutEdge::Cycle,
            ActionTarget::State(_) => {
                let id = self.graph.state_out[self.source_id.as_usize()][i];
                MutOutEdge::Expanded(MutExpandedData { graph: self.graph, state: self.state, id: id, })
            },
        }
    }
}

pub enum MutOutEdge<'a, S, A> where S: Default + 'a, A: Default + 'a {
    Cycle,
    Unexpanded(MutUnexpandedData<'a, S, A>),
    Expanded(MutExpandedData<'a, S, A>),
}

pub struct MutUnexpandedData<'a, S, A> where S: Default + 'a, A: Default + 'a {
    graph: &'a mut SearchGraph<S, A>,
    state: game::State,
    id: ArcId,
}

impl<'a, S, A> MutUnexpandedData<'a, S, A> where S: Default + 'a, A: Default + 'a {
    pub fn action(&self) -> &Action {
        &self.graph.arcs[self.id.as_usize()].action
    }

    pub fn source<'s>(&'s self) -> Node<'s, S, A> {
        let id = self.graph.arcs[self.id.as_usize()].source;
        Node { graph: self.graph, id: id, }
    }

    pub fn source_mut(self) -> MutNode<'a, S, A> {
        let id = self.graph.arcs[self.id.as_usize()].source;
        MutNode { graph: self.graph, id: id, }
    }

    pub fn expand(mut self) -> Option<MutExpandedData<'a, S, A>> {
        self.graph.expand_action_target(&self.state, self.id).map(|target_id| {
            MutExpandedData { graph: self.graph, id: target_id, }
        })
    }
}

pub struct MutExpandedData<'a, S, A> where S: Default + 'a, A: Default + 'a {
    graph: &'a mut SearchGraph<S, A>,
    state: game::State,
    id: ArcId,
}

impl<'a, S, A> MutExpandedData<'a, S, A> where S: Default + 'a, A: Default + 'a {
    pub fn action(&self) -> &Action {
        &self.graph.arcs[self.id.as_usize()].action
    }

    pub fn source<'s>(&'s self) -> Node<'s, S, A> {
        let id = self.graph.arcs[self.id.as_usize()].source;
        Node { graph: self.graph, id: id, }
    }

    pub fn source_mut(self) -> MutNode<'a, S, A> {
        let id = self.graph.arcs[self.id.as_usize()].source;
        MutNode { graph: self.graph, id: id, }
    }

    pub fn target<'s>(&'s self) -> Node<'s, S, A> {
        let id = self.graph.arcs[self.id.as_usize()].target.unwrap();
        Node { graph: self.graph, id: id, }
    }

    pub fn target_mut(self) -> MutNode<'a, S, A> {
        let id = self.graph.arcs[self.id.as_usize()].target.unwrap();
        MutNode { graph: self.graph, id: id, }
    }

    pub fn data(&self) -> &A {
        &self.graph.arc_data[self.id.as_usize()]
    }

    pub fn data_mut(&mut self) -> &mut A {
        &mut self.graph.arc_data[self.id.as_usize()]
    }
}

pub struct MutInEdgeList<'a, S, A> where S: Default + 'a, A: Default + 'a {
    graph: &'a mut SearchGraph<S, A>,
    target_id: StateId,
}

impl<'a, S, A> MutInEdgeList<'a, S, A> where S: Default + 'a, A: Default + 'a {
    pub fn is_empty(&self) -> bool {
        self.graph.state_in[self.target_id.as_usize()].is_empty()
    }

    pub fn len(&self) -> usize {
        self.graph.state_in[self.target_id.as_usize()].len()
    }

    pub fn get<'s>(&'s self, i: usize) -> ExpandedData<'s, S, A> {
        ExpandedData { graph: self.graph, id: self.graph.state_in[self.target_id.as_usize()][i], }
    }

    pub fn get_mut(self, i: usize) -> MutExpandedData<'a, S, A> {
        let id = self.graph.state_in[self.target_id.as_usize()][i];
        MutExpandedData { graph: self.graph, id: id, }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use cgmath::vector::*;

#[test]
fn test_from_value() {
    assert_eq!(Vec2::from_value(1), Vec2::new(1, 1));
    assert_eq!(Vec3::from_value(1), Vec3::new(1, 1, 1));
    assert_eq!(Vec4::from_value(1), Vec4::new(1, 1, 1, 1));
}

#[test]
fn test_dot() {
    assert_eq!(Vec2::new(1, 2).dot(&Vec2::new(3, 4)), 11);
    assert_eq!(Vec3::new(1, 2, 3).dot(&Vec3::new(4, 5, 6)), 32);
    assert_eq!(Vec4::new(1, 2, 3, 4).dot(&Vec4::new(5, 6, 7, 8)), 70);
}

#[test]
fn test_comp_add() {
    assert_eq!(Vec2::new(1, 2).comp_add(), 3);
    assert_eq!(Vec3::new(1, 2, 3).comp_add(), 6);
    assert_eq!(Vec4::new(1, 2, 3, 4).comp_add(), 10);

    assert_eq!(Vec2::new(3.0, 4.0).comp_add(), 7.0);
    assert_eq!(Vec3::new(4.0, 5.0, 6.0).comp_add(), 15.0);
    assert_eq!(Vec4::new(5.0, 6.0, 7.0, 8.0).comp_add(), 26.0);
}

#[test]
fn test_comp_mul() {
    assert_eq!(Vec2::new(1, 2).comp_mul(), 2);
    assert_eq!(Vec3::new(1, 2, 3).comp_mul(), 6);
    assert_eq!(Vec4::new(1, 2, 3, 4).comp_mul(), 24);

    assert_eq!(Vec2::new(3.0, 4.0).comp_mul(), 12.0);
    assert_eq!(Vec3::new(4.0, 5.0, 6.0).comp_mul(), 120.0);
    assert_eq!(Vec4::new(5.0, 6.0, 7.0, 8.0).comp_mul(), 1680.0);
}

#[test]
fn test_comp_min() {
    assert_eq!(Vec2::new(1, 2).comp_min(), 1);
    assert_eq!(Vec3::new(1, 2, 3).comp_min(), 1);
    assert_eq!(Vec4::new(1, 2, 3, 4).comp_min(), 1);

    assert_eq!(Vec2::new(3.0, 4.0).comp_min(), 3.0);
    assert_eq!(Vec3::new(4.0, 5.0, 6.0).comp_min(), 4.0);
    assert_eq!(Vec4::new(5.0, 6.0, 7.0, 8.0).comp_min(), 5.0);
}

#[test]
fn test_comp_max() {
    assert_eq!(Vec2::new(1, 2).comp_max(), 2);
    assert_eq!(Vec3::new(1, 2, 3).comp_max(), 3);
    assert_eq!(Vec4::new(1, 2, 3, 4).comp_max(), 4);

    assert_eq!(Vec2::new(3.0, 4.0).comp_max(), 4.0);
    assert_eq!(Vec3::new(4.0, 5.0, 6.0).comp_max(), 6.0);
    assert_eq!(Vec4::new(5.0, 6.0, 7.0, 8.0).comp_max(), 8.0);
}

#[test]
fn test_cross() {
    let a = Vec3::new(1, 2, 3);
    let b = Vec3::new(4, 5, 6);
    let r = Vec3::new(-3, 6, -3);
    assert_eq!(a.cross(&b), r);

    let mut a = a;
    a.cross_self(&b);
    assert_eq!(a, r);
}
<commit_msg>Add length tests<commit_after>// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use cgmath::vector::*;

#[test]
fn test_from_value() {
    assert_eq!(Vec2::from_value(1), Vec2::new(1, 1));
    assert_eq!(Vec3::from_value(1), Vec3::new(1, 1, 1));
    assert_eq!(Vec4::from_value(1), Vec4::new(1, 1, 1, 1));
}

#[test]
fn test_dot() {
    assert_eq!(Vec2::new(1, 2).dot(&Vec2::new(3, 4)), 11);
    assert_eq!(Vec3::new(1, 2, 3).dot(&Vec3::new(4, 5, 6)), 32);
    assert_eq!(Vec4::new(1, 2, 3, 4).dot(&Vec4::new(5, 6, 7, 8)), 70);
}

#[test]
fn test_comp_add() {
    assert_eq!(Vec2::new(1, 2).comp_add(), 3);
    assert_eq!(Vec3::new(1, 2, 3).comp_add(), 6);
    assert_eq!(Vec4::new(1, 2, 3, 4).comp_add(), 10);

    assert_eq!(Vec2::new(3.0, 4.0).comp_add(), 7.0);
    assert_eq!(Vec3::new(4.0, 5.0, 6.0).comp_add(), 15.0);
    assert_eq!(Vec4::new(5.0, 6.0, 7.0, 8.0).comp_add(), 26.0);
}

#[test]
fn test_comp_mul() {
    assert_eq!(Vec2::new(1, 2).comp_mul(), 2);
    assert_eq!(Vec3::new(1, 2, 3).comp_mul(), 6);
    assert_eq!(Vec4::new(1, 2, 3, 4).comp_mul(), 24);

    assert_eq!(Vec2::new(3.0, 4.0).comp_mul(), 12.0);
    assert_eq!(Vec3::new(4.0, 5.0, 6.0).comp_mul(), 120.0);
    assert_eq!(Vec4::new(5.0, 6.0, 7.0, 8.0).comp_mul(), 1680.0);
}

#[test]
fn test_comp_min() {
    assert_eq!(Vec2::new(1, 2).comp_min(), 1);
    assert_eq!(Vec3::new(1, 2, 3).comp_min(), 1);
    assert_eq!(Vec4::new(1, 2, 3, 4).comp_min(), 1);

    assert_eq!(Vec2::new(3.0, 4.0).comp_min(), 3.0);
    assert_eq!(Vec3::new(4.0, 5.0, 6.0).comp_min(), 4.0);
    assert_eq!(Vec4::new(5.0, 6.0, 7.0, 8.0).comp_min(), 5.0);
}

#[test]
fn test_comp_max() {
    assert_eq!(Vec2::new(1, 2).comp_max(), 2);
    assert_eq!(Vec3::new(1, 2, 3).comp_max(), 3);
    assert_eq!(Vec4::new(1, 2, 3, 4).comp_max(), 4);

    assert_eq!(Vec2::new(3.0, 4.0).comp_max(), 4.0);
    assert_eq!(Vec3::new(4.0, 5.0, 6.0).comp_max(), 6.0);
    assert_eq!(Vec4::new(5.0, 6.0, 7.0, 8.0).comp_max(), 8.0);
}

#[test]
fn test_cross() {
    let a = Vec3::new(1, 2, 3);
    let b = Vec3::new(4, 5, 6);
    let r = Vec3::new(-3, 6, -3);
    assert_eq!(a.cross(&b), r);

    let mut a = a;
    a.cross_self(&b);
    assert_eq!(a, r);
}

#[cfg(test)]
mod test_length {
    use cgmath::vector::*;

    #[test]
    fn test_vec2(){
        let (a, a_res) = (Vec2::new(3.0, 4.0), 5.0); // (3, 4, 5) Pythagorean triple
        let (b, b_res) = (Vec2::new(5.0, 12.0), 13.0); // (5, 12, 13) Pythagorean triple

        assert_eq!(a.length2(), a_res * a_res);
        assert_eq!(b.length2(), b_res * b_res);

        assert_eq!(a.length(), a_res);
        assert_eq!(b.length(), b_res);
    }

    #[test]
    fn test_vec3(){
        let (a, a_res) = (Vec3::new(2.0, 3.0, 6.0), 7.0); // (2, 3, 6, 7) Pythagorean quadruple
        let (b, b_res) = (Vec3::new(1.0, 4.0, 8.0), 9.0); // (1, 4, 8, 9) Pythagorean quadruple

        assert_eq!(a.length2(), a_res * a_res);
        assert_eq!(b.length2(), b_res * b_res);

        assert_eq!(a.length(), a_res);
        assert_eq!(b.length(), b_res);
    }

    #[test]
    fn test_vec4(){
        let (a, a_res) = (Vec4::new(1.0, 2.0, 4.0, 10.0), 11.0); // (1, 2, 4, 10, 11) Pythagorean quintuple
        let (b, b_res) = (Vec4::new(1.0, 2.0, 8.0, 10.0), 13.0); // (1, 2, 8, 10, 13) Pythagorean quintuple

        assert_eq!(a.length2(), a_res * a_res);
        assert_eq!(b.length2(), b_res * b_res);

        assert_eq!(a.length(), a_res);
        assert_eq!(b.length(), b_res);
    }
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::pin::Pin;

use futures::Stream;
use tonic::transport::Server;
use tonic::{Request, Response, Status, Streaming};

use datafusion::datasource::TableProvider;
use datafusion::prelude::*;
use datafusion::{datasource::parquet::ParquetTable, physical_plan::collect};

use arrow_flight::{
    flight_service_server::FlightService, flight_service_server::FlightServiceServer,
    Action, ActionType, Criteria, Empty, FlightData, FlightDescriptor, FlightInfo,
    HandshakeRequest, HandshakeResponse, PutResult, SchemaResult, Ticket,
};

#[derive(Clone)]
pub struct FlightServiceImpl {}

#[tonic::async_trait]
impl FlightService for FlightServiceImpl {
    type HandshakeStream = Pin<
        Box<dyn Stream<Item = Result<HandshakeResponse, Status>> + Send + Sync + 'static>,
    >;
    type ListFlightsStream =
        Pin<Box<dyn Stream<Item = Result<FlightInfo, Status>> + Send + Sync + 'static>>;
    type DoGetStream =
        Pin<Box<dyn Stream<Item = Result<FlightData, Status>> + Send + Sync + 'static>>;
    type DoPutStream =
        Pin<Box<dyn Stream<Item = Result<PutResult, Status>> + Send + Sync + 'static>>;
    type DoActionStream = Pin<
        Box<
            dyn Stream<Item = Result<arrow_flight::Result, Status>>
                + Send
                + Sync
                + 'static,
        >,
    >;
    type ListActionsStream =
        Pin<Box<dyn Stream<Item = Result<ActionType, Status>> + Send + Sync + 'static>>;
    type DoExchangeStream =
        Pin<Box<dyn Stream<Item = Result<FlightData, Status>> + Send + Sync + 'static>>;

    async fn get_schema(
        &self,
        request: Request<FlightDescriptor>,
    ) -> Result<Response<SchemaResult>, Status> {
        let request = request.into_inner();

        let table = ParquetTable::try_new(&request.path[0], num_cpus::get()).unwrap();

        let options = arrow::ipc::writer::IpcWriteOptions::default();
        let schema_result = arrow_flight::utils::flight_schema_from_arrow_schema(
            table.schema().as_ref(),
            &options,
        );

        Ok(Response::new(schema_result))
    }

    async fn do_get(
        &self,
        request: Request<Ticket>,
    ) -> Result<Response<Self::DoGetStream>, Status> {
        let ticket = request.into_inner();
        match String::from_utf8(ticket.ticket.to_vec()) {
            Ok(sql) => {
                println!("do_get: {}", sql);

                // create local execution context
                let mut ctx = ExecutionContext::new();

                let testdata = arrow::util::test_util::parquet_test_data();

                // register parquet file with the execution context
                ctx.register_parquet(
                    "alltypes_plain",
                    &format!("{}/alltypes_plain.parquet", testdata),
                )
                .map_err(|e| to_tonic_err(&e))?;

                // create the query plan
                let plan = ctx
                    .create_logical_plan(&sql)
                    .and_then(|plan| ctx.optimize(&plan))
                    .and_then(|plan| ctx.create_physical_plan(&plan))
                    .map_err(|e| to_tonic_err(&e))?;

                // execute the query
                let results =
                    collect(plan.clone()).await.map_err(|e| to_tonic_err(&e))?;
                if results.is_empty() {
                    return Err(Status::internal("There were no results from ticket"));
                }

                // add an initial FlightData message that sends schema
                let options = arrow::ipc::writer::IpcWriteOptions::default();
                let schema = plan.schema();
                let schema_flight_data =
                    arrow_flight::utils::flight_data_from_arrow_schema(
                        schema.as_ref(),
                        &options,
                    );

                let mut flights: Vec<Result<FlightData, Status>> =
                    vec![Ok(schema_flight_data)];

                let mut batches: Vec<Result<FlightData, Status>> = results
                    .iter()
                    .flat_map(|batch| {
                        let (flight_dictionaries, flight_batch) =
                            arrow_flight::utils::flight_data_from_arrow_batch(
                                batch, &options,
                            );
                        flight_dictionaries
                            .into_iter()
                            .chain(std::iter::once(flight_batch))
                            .map(Ok)
                    })
                    .collect();

                // append batch vector to schema vector, so that the first message sent is the schema
                flights.append(&mut batches);

                let output = futures::stream::iter(flights);

                Ok(Response::new(Box::pin(output) as Self::DoGetStream))
            }
            Err(e) => Err(Status::invalid_argument(format!("Invalid ticket: {:?}", e))),
        }
    }

    async fn handshake(
        &self,
        _request: Request<Streaming<HandshakeRequest>>,
    ) -> Result<Response<Self::HandshakeStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn list_flights(
        &self,
        _request: Request<Criteria>,
    ) -> Result<Response<Self::ListFlightsStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn get_flight_info(
        &self,
        _request: Request<FlightDescriptor>,
    ) -> Result<Response<FlightInfo>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn do_put(
        &self,
        _request: Request<Streaming<FlightData>>,
    ) -> Result<Response<Self::DoPutStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn do_action(
        &self,
        _request: Request<Action>,
    ) -> Result<Response<Self::DoActionStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn list_actions(
        &self,
        _request: Request<Empty>,
    ) -> Result<Response<Self::ListActionsStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn do_exchange(
        &self,
        _request: Request<Streaming<FlightData>>,
    ) -> Result<Response<Self::DoExchangeStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }
}

fn to_tonic_err(e: &datafusion::error::DataFusionError) -> Status {
    Status::internal(format!("{:?}", e))
}

/// This example shows how to wrap DataFusion with `FlightService` to support looking up schema information for
/// Parquet files and executing SQL queries against them on a remote server.
/// This example is run along-side the example `flight_client`.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "0.0.0.0:50051".parse()?;
    let service = FlightServiceImpl {};

    let svc = FlightServiceServer::new(service);

    println!("Listening on {:?}", addr);

    Server::builder().add_service(svc).serve(addr).await?;

    Ok(())
}
<commit_msg>ARROW-11894: [Rust][DataFusion] Change flight server example to use DataFrame API<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::pin::Pin;

use futures::Stream;
use tonic::transport::Server;
use tonic::{Request, Response, Status, Streaming};

use datafusion::datasource::parquet::ParquetTable;
use datafusion::datasource::TableProvider;
use datafusion::prelude::*;

use arrow_flight::{
    flight_service_server::FlightService, flight_service_server::FlightServiceServer,
    Action, ActionType, Criteria, Empty, FlightData, FlightDescriptor, FlightInfo,
    HandshakeRequest, HandshakeResponse, PutResult, SchemaResult, Ticket,
};

#[derive(Clone)]
pub struct FlightServiceImpl {}

#[tonic::async_trait]
impl FlightService for FlightServiceImpl {
    type HandshakeStream = Pin<
        Box<dyn Stream<Item = Result<HandshakeResponse, Status>> + Send + Sync + 'static>,
    >;
    type ListFlightsStream =
        Pin<Box<dyn Stream<Item = Result<FlightInfo, Status>> + Send + Sync + 'static>>;
    type DoGetStream =
        Pin<Box<dyn Stream<Item = Result<FlightData, Status>> + Send + Sync + 'static>>;
    type DoPutStream =
        Pin<Box<dyn Stream<Item = Result<PutResult, Status>> + Send + Sync + 'static>>;
    type DoActionStream = Pin<
        Box<
            dyn Stream<Item = Result<arrow_flight::Result, Status>>
                + Send
                + Sync
                + 'static,
        >,
    >;
    type ListActionsStream =
        Pin<Box<dyn Stream<Item = Result<ActionType, Status>> + Send + Sync + 'static>>;
    type DoExchangeStream =
        Pin<Box<dyn Stream<Item = Result<FlightData, Status>> + Send + Sync + 'static>>;

    async fn get_schema(
        &self,
        request: Request<FlightDescriptor>,
    ) -> Result<Response<SchemaResult>, Status> {
        let request = request.into_inner();

        let table = ParquetTable::try_new(&request.path[0], num_cpus::get()).unwrap();

        let options = arrow::ipc::writer::IpcWriteOptions::default();
        let schema_result = arrow_flight::utils::flight_schema_from_arrow_schema(
            table.schema().as_ref(),
            &options,
        );

        Ok(Response::new(schema_result))
    }

    async fn do_get(
        &self,
        request: Request<Ticket>,
    ) -> Result<Response<Self::DoGetStream>, Status> {
        let ticket = request.into_inner();
        match std::str::from_utf8(&ticket.ticket) {
            Ok(sql) => {
                println!("do_get: {}", sql);

                // create local execution context
                let mut ctx = ExecutionContext::new();

                let testdata = arrow::util::test_util::parquet_test_data();

                // register parquet file with the execution context
                ctx.register_parquet(
                    "alltypes_plain",
                    &format!("{}/alltypes_plain.parquet", testdata),
                )
                .map_err(to_tonic_err)?;

                // create the DataFrame
                let df = ctx.sql(sql).map_err(to_tonic_err)?;

                // execute the query
                let results = df.collect().await.map_err(to_tonic_err)?;
                if results.is_empty() {
                    return Err(Status::internal("There were no results from ticket"));
                }

                // add an initial FlightData message that sends schema
                let options = arrow::ipc::writer::IpcWriteOptions::default();
                let schema_flight_data =
                    arrow_flight::utils::flight_data_from_arrow_schema(
                        &df.schema().clone().into(),
                        &options,
                    );

                let mut flights: Vec<Result<FlightData, Status>> =
                    vec![Ok(schema_flight_data)];

                let mut batches: Vec<Result<FlightData, Status>> = results
                    .iter()
                    .flat_map(|batch| {
                        let (flight_dictionaries, flight_batch) =
                            arrow_flight::utils::flight_data_from_arrow_batch(
                                batch, &options,
                            );
                        flight_dictionaries
                            .into_iter()
                            .chain(std::iter::once(flight_batch))
                            .map(Ok)
                    })
                    .collect();

                // append batch vector to schema vector, so that the first message sent is the schema
                flights.append(&mut batches);

                let output = futures::stream::iter(flights);

                Ok(Response::new(Box::pin(output) as Self::DoGetStream))
            }
            Err(e) => Err(Status::invalid_argument(format!("Invalid ticket: {:?}", e))),
        }
    }

    async fn handshake(
        &self,
        _request: Request<Streaming<HandshakeRequest>>,
    ) -> Result<Response<Self::HandshakeStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn list_flights(
        &self,
        _request: Request<Criteria>,
    ) -> Result<Response<Self::ListFlightsStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn get_flight_info(
        &self,
        _request: Request<FlightDescriptor>,
    ) -> Result<Response<FlightInfo>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn do_put(
        &self,
        _request: Request<Streaming<FlightData>>,
    ) -> Result<Response<Self::DoPutStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn do_action(
        &self,
        _request: Request<Action>,
    ) -> Result<Response<Self::DoActionStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn list_actions(
        &self,
        _request: Request<Empty>,
    ) -> Result<Response<Self::ListActionsStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }

    async fn do_exchange(
        &self,
        _request: Request<Streaming<FlightData>>,
    ) -> Result<Response<Self::DoExchangeStream>, Status> {
        Err(Status::unimplemented("Not yet implemented"))
    }
}

fn to_tonic_err(e: datafusion::error::DataFusionError) -> Status {
    Status::internal(format!("{:?}", e))
}

/// This example shows how to wrap DataFusion with `FlightService` to support looking up schema information for
/// Parquet files and executing SQL queries against them on a remote server.
/// This example is run along-side the example `flight_client`.
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let addr = "0.0.0.0:50051".parse()?;
    let service = FlightServiceImpl {};

    let svc = FlightServiceServer::new(service);

    println!("Listening on {:?}", addr);

    Server::builder().add_service(svc).serve(addr).await?;

    Ok(())
}
<|endoftext|>


<commit_before>//! Organizing processes as groups and communicators
//!
//! Upon initialization of the library (via `initialize()` or `initialize_with_threading()`) a
//! singleton communication `Universe` is created. All parallel processes initially partaking in
//! the computation are organized in a context called the 'world communicator' which is available
//! as a property of the `Universe`. From the world communicator, other communicators can be
//! created. Processes can be addressed via their `Rank` within a specific communicator. This
//! information is encapsulated in an `Identifier`.
//!
//! # Unfinished features
//!
//! - **6.3**: Group management
//!   - **6.3.1**: Accessors, `MPI_Group_size()`, `MPI_Group_rank()`,
//!   `MPI_Group_translate_ranks()`
//!   - **6.3.2**: Constructors, `MPI_Group_union()`, `MPI_Group_intersection()`,
//!   `MPI_Group_difference()`, `MPI_Group_incl()`, `MPI_Group_excl()`, `MPI_Group_range_incl()`,
//!   `MPI_Group_range_excl()`
//! - **6.4**: Communicator management
//!   - **6.4.2**: Constructors, `MPI_Comm_dup_with_info()`, `MPI_Comm_idup()`, `MPI_Comm_creat()`,
//!   `MPI_Comm_create_group()`, `MPI_Comm_split_type()`
//!   - **6.4.4**: Info, `MPI_Comm_set_info()`, `MPI_Comm_get_info()`
//! - **6.6**: Inter-communication
//! - **6.7**: Caching
//! - **6.8**: Naming objects
//! - **7**: Process topologies
//! - **Parts of sections**: 8, 10, 12
use std::{mem, ptr};
use std::cmp::Ordering;
use std::marker::PhantomData;

use libc::c_int;

use ffi;
use ffi::{MPI_Comm, MPI_Group};

pub mod traits;

/// Something that can identify itself as a raw MPI communicator
pub trait RawCommunicator {
    unsafe fn raw(&self) -> MPI_Comm;
}

impl<'a, C: 'a + RawCommunicator> RawCommunicator for &'a C {
    unsafe fn raw(&self) -> MPI_Comm {
        (*self).raw()
    }
}

/// Something that has a communicator associated with it
pub trait Communicator {
    type Out: RawCommunicator;
    fn communicator(&self) -> Self::Out;
}

impl<'a, C: 'a + RawCommunicator> Communicator for &'a C {
    type Out = &'a C;
    fn communicator(&self) -> Self::Out {
        self
    }
}

/// Identifies a certain process within a communicator.
pub type Rank = c_int;

/// Global context
pub struct Universe(PhantomData<()>);

impl Universe {
    /// The 'world communicator'
    ///
    /// Contains all processes initially partaking in the computation.
    ///
    /// # Examples
    /// See `examples/simple.rs`
    pub fn world(&self) -> SystemCommunicator {
        SystemCommunicator(ffi::RSMPI_COMM_WORLD)
    }

    /// Level of multithreading supported by this MPI universe
    ///
    /// See the `Threading` enum.
    ///
    /// # Examples
    /// See `examples/init_with_threading.rs`
    pub fn threading_support(&self) -> Threading {
        let mut res: c_int = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Query_thread(&mut res as *mut c_int); }
        res.into()
    }
}

impl Drop for Universe {
    fn drop(&mut self) {
        unsafe { ffi::MPI_Finalize(); }
    }
}

/// Describes the various levels of multithreading that can be supported by an MPI library.
///
/// # Examples
/// See `examples/init_with_threading.rs`
///
/// # Standard section(s)
///
/// 12.4.3
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Threading {
    /// All processes partaking in the computation are single-threaded.
    Single,
    /// Processes may be multi-threaded, but MPI functions will only ever be called from the main
    /// thread.
    Funneled,
    /// Processes may be multi-threaded, but calls to MPI functions will not be made concurrently.
    /// The user is responsible for serializing the calls.
    Serialized,
    /// Processes may be multi-threaded with no restrictions on the use of MPI functions from the
    /// threads.
    Multiple,
}

impl Threading {
    fn raw(self) -> c_int {
        use self::Threading::*;
        match self {
            Single => ffi::RSMPI_THREAD_SINGLE,
            Funneled => ffi::RSMPI_THREAD_FUNNELED,
            Serialized => ffi::RSMPI_THREAD_SERIALIZED,
            Multiple => ffi::RSMPI_THREAD_MULTIPLE
        }
    }
}

impl PartialOrd<Threading> for Threading {
    fn partial_cmp(&self, other: &Threading) -> Option<Ordering> {
        self.raw().partial_cmp(&other.raw())
    }
}

impl Ord for Threading {
    fn cmp(&self, other: &Threading) -> Ordering {
        self.raw().cmp(&other.raw())
    }
}

impl From<c_int> for Threading {
    fn from(i: c_int) -> Threading {
        use self::Threading::*;
        if i == ffi::RSMPI_THREAD_SINGLE { return Single; }
        else if i == ffi::RSMPI_THREAD_FUNNELED { return Funneled; }
        else if i == ffi::RSMPI_THREAD_SERIALIZED { return Serialized; }
        else if i == ffi::RSMPI_THREAD_MULTIPLE { return Multiple; }
        panic!("Unknown threading level: {}", i)
    }
}

fn is_initialized() -> bool {
    let mut res: c_int = unsafe { mem::uninitialized() };
    unsafe { ffi::MPI_Initialized(&mut res as *mut c_int); }
    res != 0
}

/// Initialize MPI.
///
/// If the MPI library has not been initialized so far, initializes and returns a representation
/// of the MPI communication `Universe` which provides access to additional functions.
/// Otherwise returns `None`.
///
/// Equivalent to: `initialize_with_threading(Threading::Single)`
///
/// # Examples
/// See `examples/simple.rs`
///
/// # Standard section(s)
///
/// 8.7
pub fn initialize() -> Option<Universe> {
    initialize_with_threading(Threading::Single)
    .map(|x| x.0)
}

/// Initialize MPI with desired level of multithreading support.
///
/// If the MPI library has not been initialized so far, tries to initialize with the desired level
/// of multithreading support and returns the MPI communication `Universe` with access to
/// additional functions as well as the level of multithreading actually supported by the
/// implementation. Otherwise returns `None`.
///
/// # Examples
/// See `examples/init_with_threading.rs`
///
/// # Standard section(s)
///
/// 12.4.3
pub fn initialize_with_threading(threading: Threading) -> Option<(Universe, Threading)> {
    if is_initialized() {
        None
    } else {
        let mut provided: c_int = unsafe { mem::uninitialized() };
        unsafe {
            ffi::MPI_Init_thread(ptr::null_mut(), ptr::null_mut(), threading.raw(),
                &mut provided as *mut c_int);
        }
        Some((Universe(PhantomData), provided.into()))
    }
}

/// A built-in communicator, e.g. `MPI_COMM_WORLD`
///
/// # Standard section(s)
///
/// 6.4
#[derive(Copy, Clone)]
pub struct SystemCommunicator(MPI_Comm);

impl RawCommunicator for SystemCommunicator {
    unsafe fn raw(&self) -> MPI_Comm {
        self.0
    }
}

impl Communicator for SystemCommunicator {
    type Out = SystemCommunicator;
    fn communicator(&self) -> Self::Out {
        *self
    }
}

/// A user-defined communicator
///
/// # Standard section(s)
///
/// 6.4
pub struct UserCommunicator(MPI_Comm);

impl RawCommunicator for UserCommunicator {
    unsafe fn raw(&self) -> MPI_Comm {
        self.0
    }
}

impl Drop for UserCommunicator {
    fn drop(&mut self) {
        unsafe { ffi::MPI_Comm_free(&mut self.0 as *mut MPI_Comm); }
        assert_eq!(self.0, ffi::RSMPI_COMM_NULL);
    }
}

/// A color used in a communicator split.
pub type Color = c_int;

/// A key used when determining the rank order of processes after a communicator split.
pub type Key = c_int;

/// Standard operations on communicators
pub trait CommunicatorExt: Sized + RawCommunicator {
    /// Number of processes in this communicator
    ///
    /// # Examples
    /// See `examples/simple.rs`
    ///
    /// # Standard section(s)
    ///
    /// 6.4.1
    fn size(&self) -> Rank {
        let mut res: Rank = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_size(self.raw(), &mut res as *mut c_int); }
        res
    }

    /// The `Rank` that identifies the calling process within this communicator
    ///
    /// # Examples
    /// See `examples/simple.rs`
    ///
    /// # Standard section(s)
    ///
    /// 6.4.1
    fn rank(&self) -> Rank {
        let mut res: Rank = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_rank(self.raw(), &mut res as *mut c_int); }
        res
    }

    /// Bundles a reference to this communicator with a specific `Rank` into an `Identifier`.
    ///
    /// # Examples
    /// See `examples/broadcast.rs` `examples/gather.rs` `examples/send_receive.rs`
    // FIXME: handle out-of-range ranks
    fn process_at_rank(&self, i: Rank) -> Identifier<Self> {
        Identifier { comm: self, rank: i }
    }

    /// An `Identifier` for the calling process
    fn this_process(&self) -> Identifier<Self> {
        let rank = self.rank();
        Identifier { comm: self, rank: rank }
    }

    /// Compare two communicators.
    ///
    /// See enum `CommunicatorRelation`.
    ///
    /// # Standard section(s)
    ///
    /// 6.4.1
    fn compare<C: RawCommunicator>(&self, other: &C) -> CommunicatorRelation {
        let mut res: c_int = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_compare(self.raw(), other.raw(), &mut res as *mut c_int); }
        res.into()
    }

    /// Duplicate a communicator.
    ///
    /// # Examples
    ///
    /// See `examples/duplicate.rs`
    ///
    /// # Standard section(s)
    ///
    /// 6.4.2
    fn duplicate(&self) -> UserCommunicator {
        let mut newcomm: MPI_Comm = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_dup(self.raw(), &mut newcomm as *mut MPI_Comm); }
        UserCommunicator(newcomm)
    }

    /// Split a communicator.
    ///
    /// Creates as many new communicators as distinct values of `color` are given. All processes
    /// with the same value of `color` join the same communicator.
    ///
    /// # Examples
    ///
    /// See `examples/split.rs`
    ///
    /// # Standard section(s)
    ///
    /// 6.4.2
    fn split<C: Into<Color>>(&self, color: C) -> UserCommunicator {
        self.split_with_key(color.into(), Key::default())
    }

    /// Split a communicator.
    ///
    /// Like `split()` but orders processes according to the value of `key` in the new
    /// communicators.
    ///
    /// # Standard section(s)
    ///
    /// 6.4.2
    fn split_with_key<C: Into<Color>, K: Into<Key>>(&self, color: C, key: K) -> UserCommunicator {
        let mut newcomm: MPI_Comm = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_split(self.raw(), color.into(), key.into(),
            &mut newcomm as *mut MPI_Comm);
        }
        UserCommunicator(newcomm)
    }

    /// The group associated with this communicator
    ///
    /// # Standard section(s)
    ///
    /// 6.3.2
    fn group(&self) -> Group {
        let mut group = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_group(self.raw(), &mut group as *mut MPI_Group); }
        Group(group)
    }
}

impl CommunicatorExt for SystemCommunicator { }

impl CommunicatorExt for UserCommunicator { }

/// The relation between two communicators.
///
/// # Standard section(s)
///
/// 6.4.1
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum CommunicatorRelation {
    /// Identical groups and same contexts
    Identical,
    /// Groups match in constituents and rank order, contexts differ
    Congruent,
    /// Group constituents match but rank order differs
    Similar,
    /// Otherwise
    Unequal,
}

impl From<c_int> for CommunicatorRelation {
    fn from(i: c_int) -> CommunicatorRelation {
        use self::CommunicatorRelation::*;
        // FIXME: Yuck! These should be made const.
        if i == ffi::RSMPI_IDENT { return Identical; }
        else if i == ffi::RSMPI_CONGRUENT { return Congruent; }
        else if i == ffi::RSMPI_SIMILAR { return Similar; }
        else if i == ffi::RSMPI_UNEQUAL { return Unequal; }
        panic!("Unknown communicator relation: {}", i)
    }
}

/// Identifies a process by its `Rank` within a certain communicator.
#[derive(Copy, Clone)]
pub struct Identifier<'a, C: 'a + RawCommunicator> {
    comm: &'a C,
    rank: Rank,
}

impl<'a, C: 'a + RawCommunicator> Identifier<'a, C> {
    /// The process rank
    pub fn rank(&self) -> Rank {
        self.rank
    }
}

impl<'a, C: 'a + RawCommunicator> Communicator for Identifier<'a, C> {
    type Out = &'a C;
    fn communicator(&self) -> Self::Out {
        self.comm
    }
}

/// A group of processes
///
/// # Standard section(s)
///
/// 6.2.1
pub struct Group(MPI_Group);

impl Group {
    pub unsafe fn raw(&self) -> c_int {
        self.0
    }

    /// Compare two groups.
    ///
    /// # Standard section(s)
    ///
    /// 6.3.1
    pub fn compare(&self, other: &Group) -> GroupRelation {
        let mut relation: c_int = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Group_compare(self.raw(), other.raw(), &mut relation as *mut c_int); }
        relation.into()
    }
}

impl Drop for Group {
    fn drop(&mut self) {
        unsafe { ffi::MPI_Group_free(&mut self.0 as *mut MPI_Group); }
        assert_eq!(self.0, ffi::RSMPI_GROUP_NULL);
    }
}

/// The relation between two groups.
///
/// # Standard section(s)
///
/// 6.3.1
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum GroupRelation {
    /// Identical group members in identical order
    Identical,
    /// Identical group members in different order
    Similar,
    /// Otherwise
    Unequal,
}

impl From<c_int> for GroupRelation {
    fn from(i: c_int) -> GroupRelation {
        use self::GroupRelation::*;
        // FIXME: Yuck! These should be made const.
        if i == ffi::RSMPI_IDENT { return Identical; }
        else if i == ffi::RSMPI_SIMILAR { return Similar; }
        else if i == ffi::RSMPI_UNEQUAL { return Unequal; }
        panic!("Unknown group relation: {}", i)
    }
}
<commit_msg>Fix signature of Group raw value accessor.<commit_after>//! Organizing processes as groups and communicators
//!
//! Upon initialization of the library (via `initialize()` or `initialize_with_threading()`) a
//! singleton communication `Universe` is created. All parallel processes initially partaking in
//! the computation are organized in a context called the 'world communicator' which is available
//! as a property of the `Universe`. From the world communicator, other communicators can be
//! created. Processes can be addressed via their `Rank` within a specific communicator. This
//! information is encapsulated in an `Identifier`.
//!
//! # Unfinished features
//!
//! - **6.3**: Group management
//!   - **6.3.1**: Accessors, `MPI_Group_size()`, `MPI_Group_rank()`,
//!   `MPI_Group_translate_ranks()`
//!   - **6.3.2**: Constructors, `MPI_Group_union()`, `MPI_Group_intersection()`,
//!   `MPI_Group_difference()`, `MPI_Group_incl()`, `MPI_Group_excl()`, `MPI_Group_range_incl()`,
//!   `MPI_Group_range_excl()`
//! - **6.4**: Communicator management
//!   - **6.4.2**: Constructors, `MPI_Comm_dup_with_info()`, `MPI_Comm_idup()`, `MPI_Comm_creat()`,
//!   `MPI_Comm_create_group()`, `MPI_Comm_split_type()`
//!   - **6.4.4**: Info, `MPI_Comm_set_info()`, `MPI_Comm_get_info()`
//! - **6.6**: Inter-communication
//! - **6.7**: Caching
//! - **6.8**: Naming objects
//! - **7**: Process topologies
//! - **Parts of sections**: 8, 10, 12
use std::{mem, ptr};
use std::cmp::Ordering;
use std::marker::PhantomData;

use libc::c_int;

use ffi;
use ffi::{MPI_Comm, MPI_Group};

pub mod traits;

/// Something that can identify itself as a raw MPI communicator
pub trait RawCommunicator {
    unsafe fn raw(&self) -> MPI_Comm;
}

impl<'a, C: 'a + RawCommunicator> RawCommunicator for &'a C {
    unsafe fn raw(&self) -> MPI_Comm {
        (*self).raw()
    }
}

/// Something that has a communicator associated with it
pub trait Communicator {
    type Out: RawCommunicator;
    fn communicator(&self) -> Self::Out;
}

impl<'a, C: 'a + RawCommunicator> Communicator for &'a C {
    type Out = &'a C;
    fn communicator(&self) -> Self::Out {
        self
    }
}

/// Identifies a certain process within a communicator.
pub type Rank = c_int;

/// Global context
pub struct Universe(PhantomData<()>);

impl Universe {
    /// The 'world communicator'
    ///
    /// Contains all processes initially partaking in the computation.
    ///
    /// # Examples
    /// See `examples/simple.rs`
    pub fn world(&self) -> SystemCommunicator {
        SystemCommunicator(ffi::RSMPI_COMM_WORLD)
    }

    /// Level of multithreading supported by this MPI universe
    ///
    /// See the `Threading` enum.
    ///
    /// # Examples
    /// See `examples/init_with_threading.rs`
    pub fn threading_support(&self) -> Threading {
        let mut res: c_int = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Query_thread(&mut res as *mut c_int); }
        res.into()
    }
}

impl Drop for Universe {
    fn drop(&mut self) {
        unsafe { ffi::MPI_Finalize(); }
    }
}

/// Describes the various levels of multithreading that can be supported by an MPI library.
///
/// # Examples
/// See `examples/init_with_threading.rs`
///
/// # Standard section(s)
///
/// 12.4.3
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Threading {
    /// All processes partaking in the computation are single-threaded.
    Single,
    /// Processes may be multi-threaded, but MPI functions will only ever be called from the main
    /// thread.
    Funneled,
    /// Processes may be multi-threaded, but calls to MPI functions will not be made concurrently.
    /// The user is responsible for serializing the calls.
    Serialized,
    /// Processes may be multi-threaded with no restrictions on the use of MPI functions from the
    /// threads.
    Multiple,
}

impl Threading {
    fn raw(self) -> c_int {
        use self::Threading::*;
        match self {
            Single => ffi::RSMPI_THREAD_SINGLE,
            Funneled => ffi::RSMPI_THREAD_FUNNELED,
            Serialized => ffi::RSMPI_THREAD_SERIALIZED,
            Multiple => ffi::RSMPI_THREAD_MULTIPLE
        }
    }
}

impl PartialOrd<Threading> for Threading {
    fn partial_cmp(&self, other: &Threading) -> Option<Ordering> {
        self.raw().partial_cmp(&other.raw())
    }
}

impl Ord for Threading {
    fn cmp(&self, other: &Threading) -> Ordering {
        self.raw().cmp(&other.raw())
    }
}

impl From<c_int> for Threading {
    fn from(i: c_int) -> Threading {
        use self::Threading::*;
        if i == ffi::RSMPI_THREAD_SINGLE { return Single; }
        else if i == ffi::RSMPI_THREAD_FUNNELED { return Funneled; }
        else if i == ffi::RSMPI_THREAD_SERIALIZED { return Serialized; }
        else if i == ffi::RSMPI_THREAD_MULTIPLE { return Multiple; }
        panic!("Unknown threading level: {}", i)
    }
}

fn is_initialized() -> bool {
    let mut res: c_int = unsafe { mem::uninitialized() };
    unsafe { ffi::MPI_Initialized(&mut res as *mut c_int); }
    res != 0
}

/// Initialize MPI.
///
/// If the MPI library has not been initialized so far, initializes and returns a representation
/// of the MPI communication `Universe` which provides access to additional functions.
/// Otherwise returns `None`.
///
/// Equivalent to: `initialize_with_threading(Threading::Single)`
///
/// # Examples
/// See `examples/simple.rs`
///
/// # Standard section(s)
///
/// 8.7
pub fn initialize() -> Option<Universe> {
    initialize_with_threading(Threading::Single)
    .map(|x| x.0)
}

/// Initialize MPI with desired level of multithreading support.
///
/// If the MPI library has not been initialized so far, tries to initialize with the desired level
/// of multithreading support and returns the MPI communication `Universe` with access to
/// additional functions as well as the level of multithreading actually supported by the
/// implementation. Otherwise returns `None`.
///
/// # Examples
/// See `examples/init_with_threading.rs`
///
/// # Standard section(s)
///
/// 12.4.3
pub fn initialize_with_threading(threading: Threading) -> Option<(Universe, Threading)> {
    if is_initialized() {
        None
    } else {
        let mut provided: c_int = unsafe { mem::uninitialized() };
        unsafe {
            ffi::MPI_Init_thread(ptr::null_mut(), ptr::null_mut(), threading.raw(),
                &mut provided as *mut c_int);
        }
        Some((Universe(PhantomData), provided.into()))
    }
}

/// A built-in communicator, e.g. `MPI_COMM_WORLD`
///
/// # Standard section(s)
///
/// 6.4
#[derive(Copy, Clone)]
pub struct SystemCommunicator(MPI_Comm);

impl RawCommunicator for SystemCommunicator {
    unsafe fn raw(&self) -> MPI_Comm {
        self.0
    }
}

impl Communicator for SystemCommunicator {
    type Out = SystemCommunicator;
    fn communicator(&self) -> Self::Out {
        *self
    }
}

/// A user-defined communicator
///
/// # Standard section(s)
///
/// 6.4
pub struct UserCommunicator(MPI_Comm);

impl RawCommunicator for UserCommunicator {
    unsafe fn raw(&self) -> MPI_Comm {
        self.0
    }
}

impl Drop for UserCommunicator {
    fn drop(&mut self) {
        unsafe { ffi::MPI_Comm_free(&mut self.0 as *mut MPI_Comm); }
        assert_eq!(self.0, ffi::RSMPI_COMM_NULL);
    }
}

/// A color used in a communicator split.
pub type Color = c_int;

/// A key used when determining the rank order of processes after a communicator split.
pub type Key = c_int;

/// Standard operations on communicators
pub trait CommunicatorExt: Sized + RawCommunicator {
    /// Number of processes in this communicator
    ///
    /// # Examples
    /// See `examples/simple.rs`
    ///
    /// # Standard section(s)
    ///
    /// 6.4.1
    fn size(&self) -> Rank {
        let mut res: Rank = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_size(self.raw(), &mut res as *mut c_int); }
        res
    }

    /// The `Rank` that identifies the calling process within this communicator
    ///
    /// # Examples
    /// See `examples/simple.rs`
    ///
    /// # Standard section(s)
    ///
    /// 6.4.1
    fn rank(&self) -> Rank {
        let mut res: Rank = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_rank(self.raw(), &mut res as *mut c_int); }
        res
    }

    /// Bundles a reference to this communicator with a specific `Rank` into an `Identifier`.
    ///
    /// # Examples
    /// See `examples/broadcast.rs` `examples/gather.rs` `examples/send_receive.rs`
    // FIXME: handle out-of-range ranks
    fn process_at_rank(&self, i: Rank) -> Identifier<Self> {
        Identifier { comm: self, rank: i }
    }

    /// An `Identifier` for the calling process
    fn this_process(&self) -> Identifier<Self> {
        let rank = self.rank();
        Identifier { comm: self, rank: rank }
    }

    /// Compare two communicators.
    ///
    /// See enum `CommunicatorRelation`.
    ///
    /// # Standard section(s)
    ///
    /// 6.4.1
    fn compare<C: RawCommunicator>(&self, other: &C) -> CommunicatorRelation {
        let mut res: c_int = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_compare(self.raw(), other.raw(), &mut res as *mut c_int); }
        res.into()
    }

    /// Duplicate a communicator.
    ///
    /// # Examples
    ///
    /// See `examples/duplicate.rs`
    ///
    /// # Standard section(s)
    ///
    /// 6.4.2
    fn duplicate(&self) -> UserCommunicator {
        let mut newcomm: MPI_Comm = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_dup(self.raw(), &mut newcomm as *mut MPI_Comm); }
        UserCommunicator(newcomm)
    }

    /// Split a communicator.
    ///
    /// Creates as many new communicators as distinct values of `color` are given. All processes
    /// with the same value of `color` join the same communicator.
    ///
    /// # Examples
    ///
    /// See `examples/split.rs`
    ///
    /// # Standard section(s)
    ///
    /// 6.4.2
    fn split<C: Into<Color>>(&self, color: C) -> UserCommunicator {
        self.split_with_key(color.into(), Key::default())
    }

    /// Split a communicator.
    ///
    /// Like `split()` but orders processes according to the value of `key` in the new
    /// communicators.
    ///
    /// # Standard section(s)
    ///
    /// 6.4.2
    fn split_with_key<C: Into<Color>, K: Into<Key>>(&self, color: C, key: K) -> UserCommunicator {
        let mut newcomm: MPI_Comm = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_split(self.raw(), color.into(), key.into(),
            &mut newcomm as *mut MPI_Comm);
        }
        UserCommunicator(newcomm)
    }

    /// The group associated with this communicator
    ///
    /// # Standard section(s)
    ///
    /// 6.3.2
    fn group(&self) -> Group {
        let mut group = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Comm_group(self.raw(), &mut group as *mut MPI_Group); }
        Group(group)
    }
}

impl CommunicatorExt for SystemCommunicator { }

impl CommunicatorExt for UserCommunicator { }

/// The relation between two communicators.
///
/// # Standard section(s)
///
/// 6.4.1
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum CommunicatorRelation {
    /// Identical groups and same contexts
    Identical,
    /// Groups match in constituents and rank order, contexts differ
    Congruent,
    /// Group constituents match but rank order differs
    Similar,
    /// Otherwise
    Unequal,
}

impl From<c_int> for CommunicatorRelation {
    fn from(i: c_int) -> CommunicatorRelation {
        use self::CommunicatorRelation::*;
        // FIXME: Yuck! These should be made const.
        if i == ffi::RSMPI_IDENT { return Identical; }
        else if i == ffi::RSMPI_CONGRUENT { return Congruent; }
        else if i == ffi::RSMPI_SIMILAR { return Similar; }
        else if i == ffi::RSMPI_UNEQUAL { return Unequal; }
        panic!("Unknown communicator relation: {}", i)
    }
}

/// Identifies a process by its `Rank` within a certain communicator.
#[derive(Copy, Clone)]
pub struct Identifier<'a, C: 'a + RawCommunicator> {
    comm: &'a C,
    rank: Rank,
}

impl<'a, C: 'a + RawCommunicator> Identifier<'a, C> {
    /// The process rank
    pub fn rank(&self) -> Rank {
        self.rank
    }
}

impl<'a, C: 'a + RawCommunicator> Communicator for Identifier<'a, C> {
    type Out = &'a C;
    fn communicator(&self) -> Self::Out {
        self.comm
    }
}

/// A group of processes
///
/// # Standard section(s)
///
/// 6.2.1
pub struct Group(MPI_Group);

impl Group {
    pub unsafe fn raw(&self) -> MPI_Group {
        self.0
    }

    /// Compare two groups.
    ///
    /// # Standard section(s)
    ///
    /// 6.3.1
    pub fn compare(&self, other: &Group) -> GroupRelation {
        let mut relation: c_int = unsafe { mem::uninitialized() };
        unsafe { ffi::MPI_Group_compare(self.raw(), other.raw(), &mut relation as *mut c_int); }
        relation.into()
    }
}

impl Drop for Group {
    fn drop(&mut self) {
        unsafe { ffi::MPI_Group_free(&mut self.0 as *mut MPI_Group); }
        assert_eq!(self.0, ffi::RSMPI_GROUP_NULL);
    }
}

/// The relation between two groups.
///
/// # Standard section(s)
///
/// 6.3.1
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum GroupRelation {
    /// Identical group members in identical order
    Identical,
    /// Identical group members in different order
    Similar,
    /// Otherwise
    Unequal,
}

impl From<c_int> for GroupRelation {
    fn from(i: c_int) -> GroupRelation {
        use self::GroupRelation::*;
        // FIXME: Yuck! These should be made const.
        if i == ffi::RSMPI_IDENT { return Identical; }
        else if i == ffi::RSMPI_SIMILAR { return Similar; }
        else if i == ffi::RSMPI_UNEQUAL { return Unequal; }
        panic!("Unknown group relation: {}", i)
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result;

pub trait SocketOpt {
    fn set_send_buffer_size(&self, _size: usize) -> Result<()>;
    fn send_buffer_size(&self) -> Result<usize>;
    fn set_recv_buffer_size(&self, _size: usize) -> Result<()>;
    fn recv_buffer_size(&self) -> Result<usize>;
}

#[cfg(unix)]
mod unix {
    use super::SocketOpt;

    use std::io::{Result, Error};
    use std::os::unix::io::AsRawFd;

    use nix::Error as NixError;
    use nix::sys::socket;
    use nix::sys::socket::sockopt;

    impl<T: AsRawFd> SocketOpt for T {
        fn set_send_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::SndBuf, &size).map_err(from_nix_error)
        }

        fn send_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::SndBuf).map_err(from_nix_error)
        }

        fn set_recv_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::RcvBuf, &size).map_err(from_nix_error)
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::RcvBuf).map_err(from_nix_error)
        }
    }

    fn from_nix_error(err: NixError) -> Error {
        Error::from_raw_os_error(err.errno() as i32)
    }
}

#[cfg(windows)]
mod windows {
    use std::io::Result;

    impl<T: AsRawFd> SocketOpt for T {
        fn set_send_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_send_buffer_size is not supported in windows now");
            Ok(())
        }

        fn send_buffer_size(&self) -> Result<usize> {
            error!("send_buffer_size is not supported in windows now");
            Ok(0)
        }

        fn set_recv_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_recv_buffer_size is not supported in windows now");
            Ok(())
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            error!("recv_buffer_size is not supported in windows now");
            Ok(0)
        }
    }
}

#[cfg(unix)]
pub use self::unix::*;

#[cfg(windows)]
pub use self::windows::*;

#[cfg(test)]
mod tests {
    use std::net::{SocketAddr, TcpListener as StdTcpListener, TcpStream as StdTcpStream};
    use mio::tcp::{TcpListener as MioTcpListener, TcpStream as MioTcpStream};

    use super::SocketOpt;

    #[cfg(unix)]
    #[test]
    fn test_mio_sock_opt() {
        let addr = "127.0.0.1:0".parse().unwrap();

        let server = MioTcpListener::bind(&addr).unwrap();
        let addr = &format!("{}", server.local_addr().unwrap());

        let sock = MioTcpStream::connect(&addr.parse().unwrap()).unwrap();

        // For linux, getsockopt will return doubled value set by setsockopt.
        // But for Mac OS X, getsockopt may return the same value. So we can only
        // check value changed.
        sock.set_send_buffer_size(4096).unwrap();
        let s1 = sock.send_buffer_size().unwrap();
        sock.set_send_buffer_size(8192).unwrap();
        let s2 = sock.send_buffer_size().unwrap();
        assert!(s2 != s1, format!("{} should not equal {}", s2, s1));

        sock.set_recv_buffer_size(4096).unwrap();
        let r1 = sock.recv_buffer_size().unwrap();
        sock.set_recv_buffer_size(8192).unwrap();
        let r2 = sock.recv_buffer_size().unwrap();
        assert!(r2 != r1, format!("{} should not equal {}", r2, r1));
    }

    #[cfg(unix)]
    #[test]
    fn test_std_sock_opt() {
        let server = StdTcpListener::bind("127.0.0.1:0").unwrap();
        let addr: SocketAddr = format!("{}", server.local_addr().unwrap()).parse().unwrap();

        let sock = StdTcpStream::connect(addr).unwrap();

        sock.set_send_buffer_size(4096).unwrap();
        let s1 = sock.send_buffer_size().unwrap();
        sock.set_send_buffer_size(8192).unwrap();
        let s2 = sock.send_buffer_size().unwrap();
        assert!(s2 != s1, format!("{} should not equal {}", s2, s1));

        sock.set_recv_buffer_size(4096).unwrap();
        let r1 = sock.recv_buffer_size().unwrap();
        sock.set_recv_buffer_size(8192).unwrap();
        let r2 = sock.recv_buffer_size().unwrap();
        assert!(r2 != r1, format!("{} should not equal {}", r2, r1));
    }
}
<commit_msg>Address comments<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::Result;

pub trait SocketOpt {
    fn set_send_buffer_size(&self, _size: usize) -> Result<()>;
    fn send_buffer_size(&self) -> Result<usize>;
    fn set_recv_buffer_size(&self, _size: usize) -> Result<()>;
    fn recv_buffer_size(&self) -> Result<usize>;
}

#[cfg(unix)]
mod unix {
    use super::SocketOpt;

    use std::io::{Result, Error};
    use std::os::unix::io::AsRawFd;

    use nix::Error as NixError;
    use nix::sys::socket;
    use nix::sys::socket::sockopt;

    impl<T: AsRawFd> SocketOpt for T {
        fn set_send_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::SndBuf, &size).map_err(from_nix_error)
        }

        fn send_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::SndBuf).map_err(from_nix_error)
        }

        fn set_recv_buffer_size(&self, size: usize) -> Result<()> {
            socket::setsockopt(self.as_raw_fd(), sockopt::RcvBuf, &size).map_err(from_nix_error)
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            socket::getsockopt(self.as_raw_fd(), sockopt::RcvBuf).map_err(from_nix_error)
        }
    }

    fn from_nix_error(err: NixError) -> Error {
        Error::from_raw_os_error(err.errno() as i32)
    }
}

#[cfg(windows)]
mod windows {
    use mio::tcp::TcpStream;
    use std::io::Result;

    impl SocketOpt for TcpStream {
        fn set_send_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_send_buffer_size is not supported in windows now");
            Ok(())
        }

        fn send_buffer_size(&self) -> Result<usize> {
            error!("send_buffer_size is not supported in windows now");
            Ok(0)
        }

        fn set_recv_buffer_size(&self, _size: usize) -> Result<()> {
            error!("set_recv_buffer_size is not supported in windows now");
            Ok(())
        }

        fn recv_buffer_size(&self) -> Result<usize> {
            error!("recv_buffer_size is not supported in windows now");
            Ok(0)
        }
    }
}

#[cfg(unix)]
pub use self::unix::*;

#[cfg(windows)]
pub use self::windows::*;

#[cfg(test)]
mod tests {
    use std::net::{SocketAddr, TcpListener as StdTcpListener, TcpStream as StdTcpStream};
    use mio::tcp::{TcpListener as MioTcpListener, TcpStream as MioTcpStream};

    use super::SocketOpt;

    #[cfg(unix)]
    #[test]
    fn test_sock_opt() {
        let addr = "127.0.0.1:0".parse().unwrap();

        // mio
        let mio_server = MioTcpListener::bind(&addr).unwrap();
        let mio_addr = &format!("{}", mio_server.local_addr().unwrap());
        let mio_sock = MioTcpStream::connect(&mio_addr.parse().unwrap()).unwrap();

        // For linux, getsockopt will return doubled value set by setsockopt.
        // But for Mac OS X, getsockopt may return the same value. So we can only
        // check value changed.
        mio_sock.set_send_buffer_size(4096).unwrap();
        let mio_s1 = mio_sock.send_buffer_size().unwrap();
        mio_sock.set_send_buffer_size(8192).unwrap();
        let mio_s2 = mio_sock.send_buffer_size().unwrap();
        assert!(mio_s2 != mio_s1,
                format!("{} should not equal {}", mio_s2, mio_s1));

        mio_sock.set_recv_buffer_size(4096).unwrap();
        let mio_r1 = mio_sock.recv_buffer_size().unwrap();
        mio_sock.set_recv_buffer_size(8192).unwrap();
        let mio_r2 = mio_sock.recv_buffer_size().unwrap();
        assert!(mio_r2 != mio_r1,
                format!("{} should not equal {}", mio_r2, mio_r1));

        // std
        let std_server = StdTcpListener::bind(&addr).unwrap();
        let std_addr: SocketAddr =
            (&format!("{}", std_server.local_addr().unwrap())).parse().unwrap();
        let std_sock = StdTcpStream::connect(std_addr).unwrap();

        std_sock.set_send_buffer_size(4096).unwrap();
        let std_s1 = std_sock.send_buffer_size().unwrap();
        std_sock.set_send_buffer_size(8192).unwrap();
        let std_s2 = std_sock.send_buffer_size().unwrap();
        assert!(std_s2 != std_s1,
                format!("{} should not equal {}", std_s2, std_s1));

        std_sock.set_recv_buffer_size(4096).unwrap();
        let std_r1 = std_sock.recv_buffer_size().unwrap();
        std_sock.set_recv_buffer_size(8192).unwrap();
        let std_r2 = std_sock.recv_buffer_size().unwrap();
        assert!(std_r2 != std_r1,
                format!("{} should not equal {}", std_r2, std_r1));
    }
}
<|endoftext|>


<commit_before>fn get_value(a: &usize, b: &usize, m: &Vec<Vec<u32>>) -> u32 {
    m[*a][*b]
}

enum Direction {
    Left,
    Right,
    Up,
    Down,
}

fn round_matrix(m: &Vec<Vec<u32>>) -> Vec<u32> {
    let length = m.len();
    let mut direction = 0;
    let mut a: usize = 0;
    let mut b: usize = 0;

    let mut resutl = vec![get_value(&a, &b, m)];

    b += 1;

    while a != 0 || b != 0 {
        if direction == 0 {
            resutl.push(get_value(&a, &b, m));
            if b == length - 1 {
                direction = 1;
                a += 1;
            } else {
                b += 1;
            }
            continue;
        }
        if direction == 1 {
            resutl.push(get_value(&a, &b, m));
            if a == length - 1 {
                direction = 2;
                b -= 1;
            } else {
                a += 1;
            }
            continue;
        }
        if direction == 2 {
            resutl.push(get_value(&a, &b, m));
            if b == 0 {
                direction = 3;
                a -= 1
            } else {
                b -= 1;
            }
            continue;
        }

        if direction == 3 {
            resutl.push(get_value(&a, &b, m));
            if a == 0 {
                break;
            } else {
                a -= 1;
            }
        }
    }
    resutl
}

fn round_matrix2(m: &Vec<Vec<u32>>) -> Vec<u32> {}

fn main() {
    let testa = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
    println!("{:?}", round_matrix(&testa));
}
<commit_msg>get problem<commit_after>fn get_value(a: &usize, b: &usize, m: &Vec<Vec<u32>>) -> u32 {
    m[*a][*b]
}

fn round_matrix(m: &Vec<Vec<u32>>) -> Vec<u32> {
    let length = m.len();
    let mut direction = 0;
    let mut a: usize = 0;
    let mut b: usize = 0;

    let mut resutl = vec![get_value(&a, &b, m)];

    b += 1;

    while a != 0 || b != 0 {
        if direction == 0 {
            resutl.push(get_value(&a, &b, m));
            if b == length - 1 {
                direction = 1;
                a += 1;
            } else {
                b += 1;
            }
            continue;
        }
        if direction == 1 {
            resutl.push(get_value(&a, &b, m));
            if a == length - 1 {
                direction = 2;
                b -= 1;
            } else {
                a += 1;
            }
            continue;
        }
        if direction == 2 {
            resutl.push(get_value(&a, &b, m));
            if b == 0 {
                direction = 3;
                a -= 1
            } else {
                b -= 1;
            }
            continue;
        }

        if direction == 3 {
            resutl.push(get_value(&a, &b, m));
            if a == 0 {
                break;
            } else {
                a -= 1;
            }
        }
    }
    resutl
}

/*
enum Direction<F>
where
    F: FnMut(&mut usize, &mut usize, &Vec<Vec<u32>>, &usize) -> u32,
{
    Left(F),
    Right(F),
    Up(F),
    Down(F),
}

fn UpFn(a: &mut usize, b: &mut usize, m: &Vec<Vec<u32>>, flag: &usize) -> u32 {
    let result = get_value(a, b, m);
    if *a != 0 {
        *a -= 1;
    }
    result
}

fn DownFn(a: &mut usize, b: &mut usize, m: &Vec<Vec<u32>>, flag: &usize) -> u32 {
    let result = get_value(a, b, m);
    if a != flag {
        *a += 1;
    }
    result
}

fn LeftFn(a: &mut usize, b: &mut usize, m: &Vec<Vec<u32>>, flag: &usize) -> u32 {
    let result = get_value(a, b, m);
    if *b != 0 {
        *b -= 1;
    }
    result
}
fn RightFn(a: &mut usize, b: &mut usize, m: &Vec<Vec<u32>>, flag: &usize) -> u32 {
    let result = get_value(a, b, m);
    if b != flag {
        *b += 1;
    }
    result
}

fn round_matrix2(m: &Vec<Vec<u32>>) -> Vec<u32> {
    let length = m.len();
    let mut direction = Direction::Right(RightFn);
    let mut a: usize = 0;
    let mut b: usize = 0;

    let mut resutl = vec![];

    while a != 0 || b != 0 {
        match direction {
            Direction::Right(f) => {
                resutl.push(f(&mut a, &mut b, m, &length));
                if b == length {
                    direction = Direction::Down(DownFn);
                    b -= 1;
                }
            }
            Direction::Down(f) => {
                resutl.push(f(&mut a, &mut b, m, &length));
                if b == length {
                    direction = Direction::Left(LeftFn);
                    b -= 1;
                }
            }
            Direction::Left(f) => {
                resutl.push(f(&mut a, &mut b, m, &length));
                if b == length {
                    direction = Direction::Up(UpFn);
                    b -= 1;
                }
            }
            Direction::Up(f) => {
                resutl.push(f(&mut a, &mut b, m, &length));
                if b == length {
                    break;
                }
            }
        }
    }
    resutl
}
*/

fn main() {
    let testa = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
    println!("{:?}", round_matrix(&testa));
    //println!("{:?}", round_matrix2(&testa));
}
<|endoftext|>