<commit_before>use crate::{
    channel::Reply,
    channel_status::ChannelState,
    id_sequence::IdSequence,
    pinky_swear::{Cancellable, Pinky, PinkySwear},
    Error, Result,
};
use amq_protocol::frame::AMQPFrame;
use log::trace;
use parking_lot::Mutex;
use std::{
    collections::{HashMap, VecDeque},
    fmt,
    sync::Arc,
};

pub(crate) struct ExpectedReply(
    pub(crate) Reply,
    pub(crate) Box<dyn Cancellable<Error> + Send>,
);

impl fmt::Debug for ExpectedReply {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "ExpectedReply({:?})", self.0)
    }
}

pub(crate) type SendId = u64;

#[derive(Clone, Debug)]
pub(crate) enum Priority {
    NORMAL,
    CRITICAL,
}

impl Default for Priority {
    fn default() -> Self {
        Priority::NORMAL
    }
}

#[derive(Clone, Debug, Default)]
pub(crate) struct Frames {
    inner: Arc<Mutex<Inner>>,
}

impl Frames {
    pub(crate) fn push(
        &self,
        channel_id: u16,
        priority: Priority,
        frame: AMQPFrame,
        expected_reply: Option<ExpectedReply>,
    ) -> PinkySwear<Result<()>> {
        self.inner
            .lock()
            .push(channel_id, priority, frame, expected_reply)
    }

    pub(crate) fn push_frames(
        &self,
        channel_id: u16,
        frames: Vec<(AMQPFrame, Option<AMQPFrame>)>,
    ) -> PinkySwear<Result<()>> {
        self.inner.lock().push_frames(channel_id, frames)
    }

    pub(crate) fn retry(&self, send_id: SendId, frame: AMQPFrame) {
        self.inner.lock().retry(send_id, frame);
    }

    pub(crate) fn pop(&self, flow: bool) -> Option<(SendId, AMQPFrame)> {
        self.inner.lock().pop(flow)
    }

    pub(crate) fn next_expected_reply(&self, channel_id: u16) -> Option<Reply> {
        self.inner
            .lock()
            .expected_replies
            .get_mut(&channel_id)
            .and_then(|replies| replies.pop_front())
            .map(|t| t.0)
    }

    pub(crate) fn mark_sent(&self, send_id: SendId) {
        if let Some((_, pinky)) = self.inner.lock().outbox.remove(&send_id) {
            pinky.swear(Ok(()));
        }
    }

    pub(crate) fn drop_pending(&self) {
        self.inner.lock().drop_pending();
    }

    pub(crate) fn clear_expected_replies(&self, channel_id: u16, channel_state: ChannelState) {
        self.inner
            .lock()
            .clear_expected_replies(channel_id, channel_state);
    }
}

#[derive(Debug)]
struct Inner {
    /* Header frames must follow basic.publish frames directly, otherwise rabbitmq-server send us an UNEXPECTED_FRAME */
    header_frames: VecDeque<(SendId, AMQPFrame)>,
    priority_frames: VecDeque<(SendId, AMQPFrame)>,
    frames: VecDeque<(SendId, AMQPFrame)>,
    low_prio_frames: VecDeque<(SendId, AMQPFrame, Option<AMQPFrame>)>,
    expected_replies: HashMap<u16, VecDeque<ExpectedReply>>,
    outbox: HashMap<SendId, (u16, Pinky<Result<()>>)>,
    send_id: IdSequence<SendId>,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            header_frames: VecDeque::default(),
            priority_frames: VecDeque::default(),
            frames: VecDeque::default(),
            low_prio_frames: VecDeque::default(),
            expected_replies: HashMap::default(),
            outbox: HashMap::default(),
            send_id: IdSequence::new(false),
        }
    }
}

impl Inner {
    fn push(
        &mut self,
        channel_id: u16,
        priority: Priority,
        frame: AMQPFrame,
        expected_reply: Option<ExpectedReply>,
    ) -> PinkySwear<Result<()>> {
        let send_id = if let Priority::CRITICAL = priority {
            0
        } else {
            self.send_id.next()
        };
        match priority {
            Priority::NORMAL => self.frames.push_back((send_id, frame)),
            Priority::CRITICAL => self.priority_frames.push_front((send_id, frame)),
        }
        let (promise, pinky) = PinkySwear::new();
        self.outbox.insert(send_id, (channel_id, pinky));
        if let Some(reply) = expected_reply {
            trace!(
                "channel {} state is now waiting for {:?}",
                channel_id,
                reply
            );
            self.expected_replies
                .entry(channel_id)
                .or_default()
                .push_back(reply);
        }
        promise
    }

    fn push_frames(
        &mut self,
        channel_id: u16,
        mut frames: Vec<(AMQPFrame, Option<AMQPFrame>)>,
    ) -> PinkySwear<Result<()>> {
        let (promise, pinky) = PinkySwear::new();
        let last_frame = frames.pop();

        for frame in frames {
            self.low_prio_frames.push_back((0, frame.0, frame.1));
        }
        if let Some(last_frame) = last_frame {
            let send_id = self.send_id.next();
            self.low_prio_frames
                .push_back((send_id, last_frame.0, last_frame.1));
            self.outbox.insert(send_id, (channel_id, pinky));
        } else {
            pinky.swear(Ok(()));
        }

        promise
    }

    fn pop(&mut self, flow: bool) -> Option<(SendId, AMQPFrame)> {
        if let Some(frame) = self
            .header_frames
            .pop_front()
            .or_else(|| self.priority_frames.pop_front())
            .or_else(|| self.frames.pop_front())
        {
            return Some(frame);
        }
        if flow {
            if let Some(mut frame) = self.low_prio_frames.pop_front() {
                if let Some(next_frame) = frame.2 {
                    self.header_frames.push_back((frame.0, next_frame));
                    frame.0 = 0;
                }
                return Some((frame.0, frame.1));
            }
        }
        None
    }

    fn retry(&mut self, send_id: SendId, frame: AMQPFrame) {
        if let AMQPFrame::Header(..) = &frame {
            self.header_frames.push_front((send_id, frame));
        } else {
            self.priority_frames.push_back((send_id, frame));
        }
    }

    fn drop_pending(&mut self) {
        self.header_frames.clear();
        self.priority_frames.clear();
        self.frames.clear();
        self.low_prio_frames.clear();
        for (_, replies) in self.expected_replies.drain() {
            Self::cancel_expected_replies(replies, ChannelState::Closed);
        }
        for (_, (_, pinky)) in self.outbox.drain() {
            pinky.swear(Ok(()));
        }
    }

    fn clear_expected_replies(&mut self, channel_id: u16, channel_state: ChannelState) {
        let mut outbox = HashMap::default();

        for (send_id, (chan_id, pinky)) in self.outbox.drain() {
            if chan_id == channel_id {
                pinky.swear(Err(Error::InvalidChannelState(channel_state.clone())))
            } else {
                outbox.insert(send_id, (chan_id, pinky));
            }
        }

        self.outbox = outbox;

        if let Some(replies) = self.expected_replies.remove(&channel_id) {
            Self::cancel_expected_replies(replies, channel_state);
        }
    }

    fn cancel_expected_replies(replies: VecDeque<ExpectedReply>, channel_state: ChannelState) {
        for ExpectedReply(_, cancel) in replies {
            cancel.cancel(Error::InvalidChannelState(channel_state.clone()));
        }
    }
}
<commit_msg>don't cancel frames that don't expect a reply on channel close<commit_after>use crate::{
    channel::Reply,
    channel_status::ChannelState,
    id_sequence::IdSequence,
    pinky_swear::{Cancellable, Pinky, PinkySwear},
    Error, Result,
};
use amq_protocol::frame::AMQPFrame;
use log::trace;
use parking_lot::Mutex;
use std::{
    collections::{HashMap, VecDeque},
    fmt,
    sync::Arc,
};

pub(crate) struct ExpectedReply(
    pub(crate) Reply,
    pub(crate) Box<dyn Cancellable<Error> + Send>,
);

impl fmt::Debug for ExpectedReply {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "ExpectedReply({:?})", self.0)
    }
}

pub(crate) type SendId = u64;

#[derive(Clone, Debug)]
pub(crate) enum Priority {
    NORMAL,
    CRITICAL,
}

impl Default for Priority {
    fn default() -> Self {
        Priority::NORMAL
    }
}

#[derive(Clone, Debug, Default)]
pub(crate) struct Frames {
    inner: Arc<Mutex<Inner>>,
}

impl Frames {
    pub(crate) fn push(
        &self,
        channel_id: u16,
        priority: Priority,
        frame: AMQPFrame,
        expected_reply: Option<ExpectedReply>,
    ) -> PinkySwear<Result<()>> {
        self.inner
            .lock()
            .push(channel_id, priority, frame, expected_reply)
    }

    pub(crate) fn push_frames(
        &self,
        channel_id: u16,
        frames: Vec<(AMQPFrame, Option<AMQPFrame>)>,
    ) -> PinkySwear<Result<()>> {
        self.inner.lock().push_frames(channel_id, frames)
    }

    pub(crate) fn retry(&self, send_id: SendId, frame: AMQPFrame) {
        self.inner.lock().retry(send_id, frame);
    }

    pub(crate) fn pop(&self, flow: bool) -> Option<(SendId, AMQPFrame)> {
        self.inner.lock().pop(flow)
    }

    pub(crate) fn next_expected_reply(&self, channel_id: u16) -> Option<Reply> {
        self.inner
            .lock()
            .expected_replies
            .get_mut(&channel_id)
            .and_then(|replies| replies.pop_front())
            .map(|t| t.0)
    }

    pub(crate) fn mark_sent(&self, send_id: SendId) {
        if let Some((_, pinky, _)) = self.inner.lock().outbox.remove(&send_id) {
            pinky.swear(Ok(()));
        }
    }

    pub(crate) fn drop_pending(&self) {
        self.inner.lock().drop_pending();
    }

    pub(crate) fn clear_expected_replies(&self, channel_id: u16, channel_state: ChannelState) {
        self.inner
            .lock()
            .clear_expected_replies(channel_id, channel_state);
    }
}

#[derive(Debug)]
struct Inner {
    /* Header frames must follow basic.publish frames directly, otherwise rabbitmq-server send us an UNEXPECTED_FRAME */
    header_frames: VecDeque<(SendId, AMQPFrame)>,
    priority_frames: VecDeque<(SendId, AMQPFrame)>,
    frames: VecDeque<(SendId, AMQPFrame)>,
    low_prio_frames: VecDeque<(SendId, AMQPFrame, Option<AMQPFrame>)>,
    expected_replies: HashMap<u16, VecDeque<ExpectedReply>>,
    outbox: HashMap<SendId, (u16, Pinky<Result<()>>, bool)>,
    send_id: IdSequence<SendId>,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            header_frames: VecDeque::default(),
            priority_frames: VecDeque::default(),
            frames: VecDeque::default(),
            low_prio_frames: VecDeque::default(),
            expected_replies: HashMap::default(),
            outbox: HashMap::default(),
            send_id: IdSequence::new(false),
        }
    }
}

impl Inner {
    fn push(
        &mut self,
        channel_id: u16,
        priority: Priority,
        frame: AMQPFrame,
        expected_reply: Option<ExpectedReply>,
    ) -> PinkySwear<Result<()>> {
        let send_id = if let Priority::CRITICAL = priority {
            0
        } else {
            self.send_id.next()
        };
        match priority {
            Priority::NORMAL => self.frames.push_back((send_id, frame)),
            Priority::CRITICAL => self.priority_frames.push_front((send_id, frame)),
        }
        let (promise, pinky) = PinkySwear::new();
        self.outbox.insert(send_id, (channel_id, pinky, expected_reply.is_some()));
        if let Some(reply) = expected_reply {
            trace!(
                "channel {} state is now waiting for {:?}",
                channel_id,
                reply
            );
            self.expected_replies
                .entry(channel_id)
                .or_default()
                .push_back(reply);
        }
        promise
    }

    fn push_frames(
        &mut self,
        channel_id: u16,
        mut frames: Vec<(AMQPFrame, Option<AMQPFrame>)>,
    ) -> PinkySwear<Result<()>> {
        let (promise, pinky) = PinkySwear::new();
        let last_frame = frames.pop();

        for frame in frames {
            self.low_prio_frames.push_back((0, frame.0, frame.1));
        }
        if let Some(last_frame) = last_frame {
            let send_id = self.send_id.next();
            self.low_prio_frames
                .push_back((send_id, last_frame.0, last_frame.1));
            self.outbox.insert(send_id, (channel_id, pinky, false));
        } else {
            pinky.swear(Ok(()));
        }

        promise
    }

    fn pop(&mut self, flow: bool) -> Option<(SendId, AMQPFrame)> {
        if let Some(frame) = self
            .header_frames
            .pop_front()
            .or_else(|| self.priority_frames.pop_front())
            .or_else(|| self.frames.pop_front())
        {
            return Some(frame);
        }
        if flow {
            if let Some(mut frame) = self.low_prio_frames.pop_front() {
                if let Some(next_frame) = frame.2 {
                    self.header_frames.push_back((frame.0, next_frame));
                    frame.0 = 0;
                }
                return Some((frame.0, frame.1));
            }
        }
        None
    }

    fn retry(&mut self, send_id: SendId, frame: AMQPFrame) {
        if let AMQPFrame::Header(..) = &frame {
            self.header_frames.push_front((send_id, frame));
        } else {
            self.priority_frames.push_back((send_id, frame));
        }
    }

    fn drop_pending(&mut self) {
        self.header_frames.clear();
        self.priority_frames.clear();
        self.frames.clear();
        self.low_prio_frames.clear();
        for (_, replies) in self.expected_replies.drain() {
            Self::cancel_expected_replies(replies, ChannelState::Closed);
        }
        for (_, (_, pinky, _)) in self.outbox.drain() {
            pinky.swear(Ok(()));
        }
    }

    fn clear_expected_replies(&mut self, channel_id: u16, channel_state: ChannelState) {
        let mut outbox = HashMap::default();

        for (send_id, (chan_id, pinky, expects_reply)) in self.outbox.drain() {
            if chan_id == channel_id && expects_reply {
                pinky.swear(Err(Error::InvalidChannelState(channel_state.clone())))
            } else {
                outbox.insert(send_id, (chan_id, pinky, expects_reply));
            }
        }

        self.outbox = outbox;

        if let Some(replies) = self.expected_replies.remove(&channel_id) {
            Self::cancel_expected_replies(replies, channel_state);
        }
    }

    fn cancel_expected_replies(replies: VecDeque<ExpectedReply>, channel_state: ChannelState) {
        for ExpectedReply(_, cancel) in replies {
            cancel.cancel(Error::InvalidChannelState(channel_state.clone()));
        }
    }
}
<|endoftext|>


<commit_before>use acyclic_network::{Network, NodeType, NodeIndex};
use weight::Weight;
use rand::Rng;

/// Genome representing a feed-forward (acyclic) network with node type `NT`.
#[derive(Clone, Debug)]
pub struct Genome<NT: NodeType> {
    /// Represents the acyclic feed forward network, with `NT` as node type and `Weight` for the edge weights.
    /// Other than that, nodes and edges do not have any further associated information (`()`).
    network: Network<NT, Weight, ()>,
}

impl<NT: NodeType> Genome<NT> {
    pub fn new() -> Self {
        Genome { network: Network::new() }
    }

    /// Returns a reference to the feed forward network.

    pub fn network(&self) -> &Network<NT, Weight, ()> {
        &self.network
    }

    /// Connects two previously unconnected nodes by adding a link between `source_node` and `target_node` using `weight`.
    ///
    /// Does not check for cycles. Test for cycles before using this method!
    ///
    /// # Panics
    ///
    /// If one of `source_node` or `target_node` does not exist.
    ///
    /// If a connection between these nodes already exists!
    ///
    /// # Complexity
    ///
    /// O(1) because we use `add_link_unorderd`.

    pub fn add_link(&mut self, source_node: NodeIndex, target_node: NodeIndex, weight: Weight) {
        debug_assert!(!self.network.link_would_cycle(source_node, target_node));
        debug_assert!(self.network.valid_link(source_node, target_node).is_ok());

        let _link_index = self.network.add_link_unordered(source_node, target_node, weight, ());
    }

    fn random_node<R>(&self,
                      protected_nodes: usize,
                      tournament_k: usize,
                      rng: &mut R) -> Option<NodeIndex>
        where R: Rng
    {
        assert!(tournament_k > 0);

        let n = self.network.node_count();
        if protected_nodes >= n {
            return None;
        }

        let mut min_node = NodeIndex::new(rng.gen_range(protected_nodes, n));
        let mut min_degree = self.network.node(min_node).degree();
        for _ in 1..tournament_k {
            let node_idx = NodeIndex::new(rng.gen_range(protected_nodes, n));
            let degree = self.network.node(node_idx).degree();
            if  degree < min_degree {
                min_node = node_idx;
                min_degree = degree;
            }
        }

        Some(min_node)
    }

    /// Structural Mutation `AddNode`.
    ///
    /// Choose a random link and split it into two by inserting a new node in the middle.
    ///
    /// Note that the new `node_type` should allow incoming and outgoing links! Otherwise
    /// this panics!

    pub fn mutate_add_node<R>(&mut self,
                                 node_type: NT,
                                 second_link_weight: Option<Weight>,
                                 rng: &mut R)
                                 -> bool
        where R: Rng
    {
        let link_index = match self.network.random_link_index(rng) {
            Some(idx) => idx,
            None => return false,
        };

        let (orig_source_node, orig_target_node, orig_weight) = {
            let link = self.network.link(link_index);
            (link.source_node_index(), link.target_node_index(), link.weight())
        };

        // remove original link
        self.network.remove_link_at(link_index);

        // Add new "middle" node
        let middle_node = self.network.add_node(node_type, ());

        // Add two new links connecting the three nodes. This cannot add a cycle!
        //
        // The first link reuses the same weight as the original link.
        // The second link uses `second_link_weight` as weight (or if `None`, `orig_weight`).
        // Ideally this is of full strength as we want to make the modification
        // to the network (CPPN) as little as possible.

        self.add_link(orig_source_node, middle_node, orig_weight);
        self.add_link(middle_node, orig_target_node, second_link_weight.unwrap_or(orig_weight));

        return true;
    }

    /// Structural Mutation `DropNode`.
    ///
    /// Choose a random node and remove it. All in and outgoing links to and from that node
    /// are removed as well. Note that the first `protected_nodes` are not removed!
    ///
    /// We choose `tournament_k` random nodes and remove the one with the smallest degree.

    pub fn mutate_drop_node<R>(&mut self,
                               protected_nodes: usize,
                               tournament_k: usize,
                               rng: &mut R) -> bool
        where R: Rng
    {
        match self.random_node(protected_nodes, tournament_k, rng) {
            None => {
                false
            }
            Some(node_idx) => {
                self.network.remove_node(node_idx);
                true
            }
        }
    }

    /// Structural Mutation `ModifyNode`.
    ///
    /// Choose a random node and change it's type to `new_node_type`.
    ///
    /// We choose from `tournament_k` nodes the one with the smallest degree.

    pub fn mutate_modify_node<R>(&mut self,
                               new_node_type: NT,
                               protected_nodes: usize,
                               tournament_k: usize,
                               rng: &mut R) -> bool
        where R: Rng
    {
        match self.random_node(protected_nodes, tournament_k, rng) {
            None => {
                false
            }
            Some(node_idx) => {
                self.network.node_mut(node_idx).set_node_type(new_node_type);
                true
            }
        }
    }

    /// Structural Mutation `Connect`.
    ///
    /// Mutate the genome by adding a random valid link which does not introduce a cycle.
    ///
    /// Return `true` if the genome was modified. Otherwise `false`.

    pub fn mutate_connect<R>(&mut self, link_weight: Weight, rng: &mut R) -> bool
        where R: Rng
    {
        match self.network.find_random_unconnected_link_no_cycle(rng) {
            Some((source_node, target_node)) => {
                // Add new link to the genome
                self.add_link(source_node, target_node, link_weight);
                return true;
            }
            None => {
                return false;
            }
        }
    }

    /// Structural Mutation `Disconnect`.
    ///
    /// Mutate the genome by removing a random link.
    ///
    /// Return `true` if the genome was modified. Otherwise `false`.

    pub fn mutate_disconnect<R>(&mut self, rng: &mut R) -> bool
        where R: Rng
    {
        match self.network.random_link_index(rng) {
            Some(idx) => {
                self.network.remove_link_at(idx);
                true
            }
            None => false,
        }
    }
}
<commit_msg>rustfmt<commit_after>use acyclic_network::{Network, NodeType, NodeIndex};
use weight::Weight;
use rand::Rng;

/// Genome representing a feed-forward (acyclic) network with node type `NT`.
#[derive(Clone, Debug)]
pub struct Genome<NT: NodeType> {
    /// Represents the acyclic feed forward network, with `NT` as node type and `Weight` for the edge weights.
    /// Other than that, nodes and edges do not have any further associated information (`()`).
    network: Network<NT, Weight, ()>,
}

impl<NT: NodeType> Genome<NT> {
    pub fn new() -> Self {
        Genome { network: Network::new() }
    }

    /// Returns a reference to the feed forward network.

    pub fn network(&self) -> &Network<NT, Weight, ()> {
        &self.network
    }

    /// Connects two previously unconnected nodes by adding a link between `source_node` and `target_node` using `weight`.
    ///
    /// Does not check for cycles. Test for cycles before using this method!
    ///
    /// # Panics
    ///
    /// If one of `source_node` or `target_node` does not exist.
    ///
    /// If a connection between these nodes already exists!
    ///
    /// # Complexity
    ///
    /// O(1) because we use `add_link_unorderd`.

    pub fn add_link(&mut self, source_node: NodeIndex, target_node: NodeIndex, weight: Weight) {
        debug_assert!(!self.network.link_would_cycle(source_node, target_node));
        debug_assert!(self.network.valid_link(source_node, target_node).is_ok());

        let _link_index = self.network.add_link_unordered(source_node, target_node, weight, ());
    }

    fn random_node<R>(&self,
                      protected_nodes: usize,
                      tournament_k: usize,
                      rng: &mut R)
                      -> Option<NodeIndex>
        where R: Rng
    {
        assert!(tournament_k > 0);

        let n = self.network.node_count();
        if protected_nodes >= n {
            return None;
        }

        let mut min_node = NodeIndex::new(rng.gen_range(protected_nodes, n));
        let mut min_degree = self.network.node(min_node).degree();
        for _ in 1..tournament_k {
            let node_idx = NodeIndex::new(rng.gen_range(protected_nodes, n));
            let degree = self.network.node(node_idx).degree();
            if degree < min_degree {
                min_node = node_idx;
                min_degree = degree;
            }
        }

        Some(min_node)
    }

    /// Structural Mutation `AddNode`.
    ///
    /// Choose a random link and split it into two by inserting a new node in the middle.
    ///
    /// Note that the new `node_type` should allow incoming and outgoing links! Otherwise
    /// this panics!

    pub fn mutate_add_node<R>(&mut self,
                              node_type: NT,
                              second_link_weight: Option<Weight>,
                              rng: &mut R)
                              -> bool
        where R: Rng
    {
        let link_index = match self.network.random_link_index(rng) {
            Some(idx) => idx,
            None => return false,
        };

        let (orig_source_node, orig_target_node, orig_weight) = {
            let link = self.network.link(link_index);
            (link.source_node_index(),
             link.target_node_index(),
             link.weight())
        };

        // remove original link
        self.network.remove_link_at(link_index);

        // Add new "middle" node
        let middle_node = self.network.add_node(node_type, ());

        // Add two new links connecting the three nodes. This cannot add a cycle!
        //
        // The first link reuses the same weight as the original link.
        // The second link uses `second_link_weight` as weight (or if `None`, `orig_weight`).
        // Ideally this is of full strength as we want to make the modification
        // to the network (CPPN) as little as possible.

        self.add_link(orig_source_node, middle_node, orig_weight);
        self.add_link(middle_node,
                      orig_target_node,
                      second_link_weight.unwrap_or(orig_weight));

        return true;
    }

    /// Structural Mutation `DropNode`.
    ///
    /// Choose a random node and remove it. All in and outgoing links to and from that node
    /// are removed as well. Note that the first `protected_nodes` are not removed!
    ///
    /// We choose `tournament_k` random nodes and remove the one with the smallest degree.

    pub fn mutate_drop_node<R>(&mut self,
                               protected_nodes: usize,
                               tournament_k: usize,
                               rng: &mut R)
                               -> bool
        where R: Rng
    {
        match self.random_node(protected_nodes, tournament_k, rng) {
            None => false,
            Some(node_idx) => {
                self.network.remove_node(node_idx);
                true
            }
        }
    }

    /// Structural Mutation `ModifyNode`.
    ///
    /// Choose a random node and change it's type to `new_node_type`.
    ///
    /// We choose from `tournament_k` nodes the one with the smallest degree.

    pub fn mutate_modify_node<R>(&mut self,
                                 new_node_type: NT,
                                 protected_nodes: usize,
                                 tournament_k: usize,
                                 rng: &mut R)
                                 -> bool
        where R: Rng
    {
        match self.random_node(protected_nodes, tournament_k, rng) {
            None => false,
            Some(node_idx) => {
                self.network.node_mut(node_idx).set_node_type(new_node_type);
                true
            }
        }
    }

    /// Structural Mutation `Connect`.
    ///
    /// Mutate the genome by adding a random valid link which does not introduce a cycle.
    ///
    /// Return `true` if the genome was modified. Otherwise `false`.

    pub fn mutate_connect<R>(&mut self, link_weight: Weight, rng: &mut R) -> bool
        where R: Rng
    {
        match self.network.find_random_unconnected_link_no_cycle(rng) {
            Some((source_node, target_node)) => {
                // Add new link to the genome
                self.add_link(source_node, target_node, link_weight);
                return true;
            }
            None => {
                return false;
            }
        }
    }

    /// Structural Mutation `Disconnect`.
    ///
    /// Mutate the genome by removing a random link.
    ///
    /// Return `true` if the genome was modified. Otherwise `false`.

    pub fn mutate_disconnect<R>(&mut self, rng: &mut R) -> bool
        where R: Rng
    {
        match self.network.random_link_index(rng) {
            Some(idx) => {
                self.network.remove_link_at(idx);
                true
            }
            None => false,
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use hyper::Client;
use hubcaps::{Github, ReleaseOptions};
use error::Error;
use super::USERAGENT;

pub fn release(tag_name: &str, tag_message: &str) -> Result<(), Error> {
    let token = try!(env::var("GITHUB_TOKEN"));

    let client = Client::new();
    let github = Github::new(USERAGENT, &client, Some(token));

    let user = "badboy";
    let repo = "test-project";
    let branch = "master"; // TODO: Extract from environment, might be != master

    let opts = ReleaseOptions::builder(tag_name)
        .name(tag_name)
        .body(tag_message)
        .commitish(branch)
        .draft(false)
        .prerelease(false)
        .build();

    let repo = github.repo(user, repo);
    let release = repo.releases();

    release
        .create(&opts)
        .map(|_| ())
        .map_err(Error::from)
}
<commit_msg>style: Make sure it doesn't try the wrong repository<commit_after>use std::env;
use hyper::Client;
use hubcaps::{Github, ReleaseOptions};
use error::Error;
use super::USERAGENT;

pub fn release(tag_name: &str, tag_message: &str) -> Result<(), Error> {
    let token = try!(env::var("GITHUB_TOKEN"));

    let client = Client::new();
    let github = Github::new(USERAGENT, &client, Some(token));

    // TODO: Get user and repo
    let user = "";
    let repo = "";
    let branch = "master"; // TODO: Extract from environment, might be != master

    let opts = ReleaseOptions::builder(tag_name)
        .name(tag_name)
        .body(tag_message)
        .commitish(branch)
        .draft(false)
        .prerelease(false)
        .build();

    let repo = github.repo(user, repo);
    let release = repo.releases();

    release
        .create(&opts)
        .map(|_| ())
        .map_err(Error::from)
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::CString;
use std::os::unix::ffi::{OsStrExt, OsStringExt};
use std::path::PathBuf;

use libc;

// In C this would be simple getenv(). Not in Rust though
pub fn getenv(var: &str) -> Option<CString> {
    if let Some(value) = env::var_os(var) {
        let value = value.as_os_str().as_bytes();
        CString::new(value).ok()
    } else {
        None
    }
    // let to_bytes = |x: &OsString| x.as_os_str().as_bytes();
    // let to_bytes = |x: &OsString| x.into::<Vec<u8>>();
    // env::var_os(&self.env).map(to_bytes).and_then(|x| CString::new(x).ok())
}

// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

pub fn execvp(argv: Vec<*const libc::c_char>) {
    assert!(unsafe { libc::execvp(argv[0], argv.as_ptr()) } > -1);
}

pub fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

pub fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

pub fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}

fn which(exec: &str) -> Option<PathBuf> {
    if let Some(path) = env::var_os("PATH") {
        let paths = env::split_paths(&path);
        for path in paths {
            let candidate = path.join(exec);
            if path.join(exec).exists() {
                return Some(candidate);
            }
        }
    }
    None
}

pub fn default_pager() -> Option<CString> {
    which("more")
        .map(|p| p.into_os_string().into_vec())
        .and_then(|s| CString::new(s).ok())
}

#[cfg(test)]
mod tests {
    use super::{default_pager, which};
    use std::ffi::CString;
    use std::path::PathBuf;

    #[test]
    fn more_found_in_path() {
        assert!(which("more").is_some())
    }

    #[test]
    fn erom_not_found_in_path() {
        assert!(which("erom").is_none())
    }

    #[test]
    fn which_more() {
        assert_eq!(which("more"), Some(PathBuf::from("/usr/bin/more")));
    }

    #[test]
    fn usr_bin_more_default_pager() {
        let usr_bin_more = CString::new("/usr/bin/more").unwrap();
        assert_eq!(default_pager(), Some(usr_bin_more));
    }
}
<commit_msg>Fix tests on Linux<commit_after>use std::env;
use std::ffi::CString;
use std::os::unix::ffi::{OsStrExt, OsStringExt};
use std::path::PathBuf;

use libc;

// In C this would be simple getenv(). Not in Rust though
pub fn getenv(var: &str) -> Option<CString> {
    if let Some(value) = env::var_os(var) {
        let value = value.as_os_str().as_bytes();
        CString::new(value).ok()
    } else {
        None
    }
    // let to_bytes = |x: &OsString| x.as_os_str().as_bytes();
    // let to_bytes = |x: &OsString| x.into::<Vec<u8>>();
    // env::var_os(&self.env).map(to_bytes).and_then(|x| CString::new(x).ok())
}

// Helper wrappers around libc::* API
pub fn fork() -> libc::pid_t {
    unsafe { libc::fork() }
}

pub fn execvp(argv: Vec<*const libc::c_char>) {
    assert!(unsafe { libc::execvp(argv[0], argv.as_ptr()) } > -1);
}

pub fn dup2(fd1: i32, fd2: i32) {
    assert!(unsafe { libc::dup2(fd1, fd2) } > -1);
}

pub fn close(fd: i32) {
    assert_eq!(unsafe { libc::close(fd) }, 0);
}

pub fn pipe() -> (i32, i32) {
    let mut fds = [0; 2];
    assert_eq!(unsafe { libc::pipe(fds.as_mut_ptr()) }, 0);
    (fds[0], fds[1])
}

fn which(exec: &str) -> Option<PathBuf> {
    if let Some(path) = env::var_os("PATH") {
        let paths = env::split_paths(&path);
        for path in paths {
            let candidate = path.join(exec);
            if path.join(exec).exists() {
                return Some(candidate);
            }
        }
    }
    None
}

pub fn default_pager() -> Option<CString> {
    which("more")
        .map(|p| p.into_os_string().into_vec())
        .and_then(|s| CString::new(s).ok())
}

#[cfg(test)]
mod tests {
    use super::{default_pager, which};
    use std::ffi::CString;
    use std::path::PathBuf;

#[cfg(target_os = "linux")]
const MORE: &'static str = "/bin/more";

#[cfg(target_os = "macos")]
const MORE: &'static str = "/usr/bin/more";

    #[test]
    fn more_found_in_path() {
        assert!(which("more").is_some())
    }

    #[test]
    fn erom_not_found_in_path() {
        assert!(which("erom").is_none())
    }

    #[test]
    fn which_more() {
        assert_eq!(which("more"), Some(PathBuf::from(MORE)));
    }

    #[test]
    fn usr_bin_more_default_pager() {
        let more = CString::new(MORE).unwrap();
        assert_eq!(default_pager(), Some(more));
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::{vec_deque, VecDeque};
use std::rc::Rc;
use std::str;

use crate::bam;
use crate::bam::Read;
use crate::errors::{Error, Result};

/// A buffer for BAM records. This allows access regions in a sorted BAM file while iterating
/// over it in a single pass.
/// The buffer is implemented as a ringbuffer, such that extension or movement to the right has
/// linear complexity. The buffer makes use of indexed random access. Hence, when fetching a
/// region at the very end of the BAM, everything before is omitted without cost.
#[derive(Debug)]
pub struct RecordBuffer {
    reader: bam::IndexedReader,
    inner: VecDeque<Rc<bam::Record>>,
    overflow: Option<Rc<bam::Record>>,
    cache_cigar: bool,
}

unsafe impl Sync for RecordBuffer {}
unsafe impl Send for RecordBuffer {}

impl RecordBuffer {
    /// Create a new `RecordBuffer`.
    ///
    /// # Arguments
    ///
    /// * `bam` - BAM reader
    /// * `cache_cigar` - whether to call `bam::Record::cache_cigar()` for each record.
    pub fn new(bam: bam::IndexedReader, cache_cigar: bool) -> Self {
        RecordBuffer {
            reader: bam,
            inner: VecDeque::new(),
            overflow: None,
            cache_cigar,
        }
    }

    /// Return start position of buffer
    fn start(&self) -> Option<u64> {
        self.inner.front().map(|rec| rec.pos() as u64)
    }

    /// Return end position of buffer.
    fn end(&self) -> Option<u64> {
        self.inner.back().map(|rec| rec.pos() as u64)
    }

    fn tid(&self) -> Option<i32> {
        self.inner.back().map(|rec| rec.tid())
    }

    /// Fill buffer at the given interval. If the start coordinate is left of
    /// the previous start coordinate, this will use an additional BAM fetch IO operation.
    /// Coordinates are 0-based, and end is exclusive.
    /// Returns tuple with numbers of added and deleted records since the previous fetch.
    #[allow(unused_assignments)] // TODO this is needed because rustc thinks that deleted is unused
    pub fn fetch(&mut self, chrom: &[u8], start: u64, end: u64) -> Result<(usize, usize)> {
        let mut added = 0;
        // move overflow from last fetch into ringbuffer
        if self.overflow.is_some() {
            added += 1;
            self.inner.push_back(self.overflow.take().unwrap());
        }

        if let Some(tid) = self.reader.header.tid(chrom) {
            let mut deleted = 0;
            let window_start = start;
            if self.inner.is_empty()
                || self.end().unwrap() < window_start
                || self.tid().unwrap() != tid as i32
                || self.start().unwrap() > window_start
            {
                let end = self.reader.header.target_len(tid).unwrap();
                self.reader.fetch((tid, window_start, end))?;
                deleted = self.inner.len();
                self.inner.clear();
            } else {
                // remove records too far left
                let to_remove = self
                    .inner
                    .iter()
                    .take_while(|rec| rec.pos() < window_start as i64)
                    .count();
                for _ in 0..to_remove {
                    self.inner.pop_front();
                }
                deleted = to_remove;
            }

            // extend to the right
            loop {
                let mut record = Rc::new(bam::Record::new());
                if self
                    .reader
                    .read(Rc::get_mut(&mut record).unwrap())
                    .is_none()
                {
                    break;
                }

                if record.is_unmapped() {
                    continue;
                }

                let pos = record.pos();

                if self.cache_cigar {
                    Rc::get_mut(&mut record).unwrap().cache_cigar();
                }

                if pos >= end as i64 {
                    self.overflow = Some(record);
                    break;
                } else {
                    self.inner.push_back(record);
                    added += 1;
                }
            }

            Ok((added, deleted))
        } else {
            Err(Error::UnknownSequence {
                sequence: str::from_utf8(chrom).unwrap().to_owned(),
            })
        }
    }

    /// Iterate over records that have been fetched with `fetch`.
    pub fn iter<'a>(&'a self) -> vec_deque::Iter<'a, Rc<bam::Record>> {
        self.inner.iter()
    }

    /// Iterate over mutable references to records that have been fetched with `fetch`.
    pub fn iter_mut<'a>(&'a mut self) -> vec_deque::IterMut<'a, Rc<bam::Record>> {
        self.inner.iter_mut()
    }

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

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

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

    #[test]
    fn test_buffer() {
        let reader = bam::IndexedReader::from_path(&"test/test.bam").unwrap();

        let mut buffer = RecordBuffer::new(reader, false);

        buffer.fetch(b"CHROMOSOME_I", 1, 5).unwrap();
        {
            let records: Vec<_> = buffer.iter().collect();
            assert_eq!(records.len(), 6);
            assert_eq!(records[0].pos(), 1);
            assert_eq!(records[1].pos(), 1);
            assert_eq!(records[2].pos(), 1);
            assert_eq!(records[3].pos(), 1);
            assert_eq!(records[4].pos(), 1);
            assert_eq!(records[5].pos(), 1);
        }
    }
}
<commit_msg>allow to set minimum distance for refetching in bam::RecordBuffer.<commit_after>// Copyright 2017 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::{vec_deque, VecDeque};
use std::rc::Rc;
use std::str;

use crate::bam;
use crate::bam::Read;
use crate::errors::{Error, Result};

/// A buffer for BAM records. This allows access regions in a sorted BAM file while iterating
/// over it in a single pass.
/// The buffer is implemented as a ringbuffer, such that extension or movement to the right has
/// linear complexity. The buffer makes use of indexed random access. Hence, when fetching a
/// region at the very end of the BAM, everything before is omitted without cost.
#[derive(Debug)]
pub struct RecordBuffer {
    reader: bam::IndexedReader,
    inner: VecDeque<Rc<bam::Record>>,
    overflow: Option<Rc<bam::Record>>,
    cache_cigar: bool,
    min_refetch_distance: u64,
}

unsafe impl Sync for RecordBuffer {}
unsafe impl Send for RecordBuffer {}

impl RecordBuffer {
    /// Create a new `RecordBuffer`.
    ///
    /// # Arguments
    ///
    /// * `bam` - BAM reader
    /// * `cache_cigar` - whether to call `bam::Record::cache_cigar()` for each record.
    pub fn new(bam: bam::IndexedReader, cache_cigar: bool) -> Self {
        RecordBuffer {
            reader: bam,
            inner: VecDeque::new(),
            overflow: None,
            cache_cigar,
            min_refetch_distance: 1,
        }
    }

    /// maximum distance to previous fetch window such that a
    /// new fetch operation is performed. If the distance is smaller, buffer will simply
    /// read through until the start of the new fetch window (probably saving some time
    /// by avoiding the random access).
    pub fn set_min_refetch_distance(&mut self, min_refetch_distance: u64) {
        self.min_refetch_distance = min_refetch_distance;
    }

    /// Return start position of buffer
    fn start(&self) -> Option<u64> {
        self.inner.front().map(|rec| rec.pos() as u64)
    }

    /// Return end position of buffer.
    fn end(&self) -> Option<u64> {
        self.inner.back().map(|rec| rec.pos() as u64)
    }

    fn tid(&self) -> Option<i32> {
        self.inner.back().map(|rec| rec.tid())
    }

    /// Fill buffer at the given interval. If the start coordinate is left of
    /// the previous start coordinate, this will use an additional BAM fetch IO operation.
    /// Coordinates are 0-based, and end is exclusive.
    /// Returns tuple with numbers of added and deleted records since the previous fetch.
    #[allow(unused_assignments)] // TODO this is needed because rustc thinks that deleted is unused
    pub fn fetch(&mut self, chrom: &[u8], start: u64, end: u64) -> Result<(usize, usize)> {
        let mut added = 0;
        // move overflow from last fetch into ringbuffer
        if self.overflow.is_some() {
            added += 1;
            self.inner.push_back(self.overflow.take().unwrap());
        }

        if let Some(tid) = self.reader.header.tid(chrom) {
            let mut deleted = 0;
            let window_start = start;
            if self.inner.is_empty()
                || window_start.saturating_sub(self.end().unwrap()) >= self.min_refetch_distance
                || self.tid().unwrap() != tid as i32
                || self.start().unwrap() > window_start
            {
                let end = self.reader.header.target_len(tid).unwrap();
                self.reader.fetch((tid, window_start, end))?;
                deleted = self.inner.len();
                self.inner.clear();
            } else {
                // remove records too far left
                let to_remove = self
                    .inner
                    .iter()
                    .take_while(|rec| rec.pos() < window_start as i64)
                    .count();
                for _ in 0..to_remove {
                    self.inner.pop_front();
                }
                deleted = to_remove;
            }

            // extend to the right
            loop {
                let mut record = Rc::new(bam::Record::new());
                if self
                    .reader
                    .read(Rc::get_mut(&mut record).unwrap())
                    .is_none()
                {
                    break;
                }

                if record.is_unmapped() {
                    continue;
                }

                let pos = record.pos();

                // skip records before the start
                if pos < start as i64 {
                    continue;
                }

                if self.cache_cigar {
                    Rc::get_mut(&mut record).unwrap().cache_cigar();
                }

                if pos >= end as i64 {
                    self.overflow = Some(record);
                    break;
                } else {
                    self.inner.push_back(record);
                    added += 1;
                }
            }

            Ok((added, deleted))
        } else {
            Err(Error::UnknownSequence {
                sequence: str::from_utf8(chrom).unwrap().to_owned(),
            })
        }
    }

    /// Iterate over records that have been fetched with `fetch`.
    pub fn iter<'a>(&'a self) -> vec_deque::Iter<'a, Rc<bam::Record>> {
        self.inner.iter()
    }

    /// Iterate over mutable references to records that have been fetched with `fetch`.
    pub fn iter_mut<'a>(&'a mut self) -> vec_deque::IterMut<'a, Rc<bam::Record>> {
        self.inner.iter_mut()
    }

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

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

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

    #[test]
    fn test_buffer() {
        let reader = bam::IndexedReader::from_path(&"test/test.bam").unwrap();
        let mut buffer = RecordBuffer::new(reader, false);

        buffer.fetch(b"CHROMOSOME_I", 1, 5).unwrap();
        {
            let records: Vec<_> = buffer.iter().collect();
            assert_eq!(records.len(), 6);
            assert_eq!(records[0].pos(), 1);
            assert_eq!(records[1].pos(), 1);
            assert_eq!(records[2].pos(), 1);
            assert_eq!(records[3].pos(), 1);
            assert_eq!(records[4].pos(), 1);
            assert_eq!(records[5].pos(), 1);
        }
    }
}
<|endoftext|>


<commit_before>extern crate bincode;
extern crate rustc_serialize;
extern crate rpsrtsrs;
extern crate docopt;

use std::net::{TcpListener, TcpStream};
use std::io::Write;
use std::ops::Deref;
use std::sync::{Mutex,Arc};
use std::thread;

use docopt::Docopt;

use rpsrtsrs::state::{World, Player, Unit};
use rpsrtsrs::network::{Message};

use bincode::SizeLimit;
use bincode::rustc_serialize::{decode_from, encode};
use bincode::rustc_serialize::DecodingResult;

type SafeWorldState = Arc<Mutex<World>>;

fn handle_client(mut stream: TcpStream, world: SafeWorldState) {

    // handle client hello
    let client_message: DecodingResult<Message> = decode_from(&mut stream, SizeLimit::Bounded(128));
    match client_message {
        Ok(message) => {
            match message {
                Message::ClientHello => {
                    let mut world_lock = world.lock().unwrap();
                    let id = world_lock.game.players.last().map_or(0, |player| player.id+1);
                    // create new player for the newly connected client
                    let mut player = Player::new(id);
                    player.units.push(Unit::new([ 50, 50]));
                    player.units.push(Unit::new([ 50,100]));
                    player.units.push(Unit::new([100, 50]));
                    player.units.push(Unit::new([100,100]));
                    world_lock.game.players.push(player);

                    let encoded: Vec<u8> = encode(&Message::ServerHello(
                            id, world_lock.clone()), SizeLimit::Infinite).unwrap();
                    stream.write(&encoded).unwrap();
                },
                Message::ClientReconnect(id) => {
                    let world_lock = world.lock().unwrap();

                    match world_lock.game.players.iter().find(|player|player.id==id) {
                        Some(player) => {
                            println!("Found you :)");
                            let encoded: Vec<u8> = encode(&Message::ServerHello(
                                    id, world_lock.clone()), SizeLimit::Infinite).unwrap();
                            stream.write(&encoded).unwrap();
                        },
                        None => {
                            println!("Reconnect to id {} not possible", id);
                            let encoded: Vec<u8> = encode(&Message::Error, SizeLimit::Infinite).unwrap();
                            stream.write(&encoded).unwrap();
                            return
                        }
                    }
                },
                _ => {
                    println!("Did not receive ClientHello{:?}", message);
                    let encoded: Vec<u8> = encode(&Message::Error, SizeLimit::Infinite).unwrap();
                    stream.write(&encoded).unwrap();
                    return
                }
            }
        }
        Err(e) => {
            println!("{:?}", e);
            return
        }
    }

    // GameState loop
    loop {
        let encoded: Vec<u8> = {
            let world_lock = world.lock().unwrap();
            encode(&world_lock.game, SizeLimit::Infinite).unwrap()
        };
        match stream.write(&encoded) {
            Err(e) => {
                println!("Error: {:?}", e);
                return;
            }
            _ =>  thread::sleep_ms(1000),
        };
    }
}

fn update_world(world: SafeWorldState) {
    loop {
        {
            let mut world_lock = world.lock().unwrap();
            for player in world_lock.game.players.iter_mut() {
                for unit in player.units.iter_mut() {
                    unit.update(500);
                    println!("{:?}", unit);
                }
            }
        }
        thread::sleep_ms(500);
    }
}

static USAGE: &'static str = "
Usage: server [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 8080].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
    -r ID    Reconnect with the given ID
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i;
    let port = args.flag_p;

    let tcp_listener = TcpListener::bind((host.deref(),port)).unwrap();
    println!("Start server: {:?}", tcp_listener);

    let world = Arc::new(Mutex::new(World::new(800, 600)));
    let world_clone = world.clone();
    thread::spawn(move || {
        update_world(world_clone);
    });

    for stream in tcp_listener.incoming() {
        match stream {
            Ok(stream) => {
                let world_clone = world.clone();
                println!("Spawning thread...");
                thread::spawn(move || {
                    handle_client(stream, world_clone);
                });
            }
            Err(e) => {
                println!("{:?}", e);
            }
        }
    }
    drop(tcp_listener);
}
<commit_msg>Fix compilation warnings (#20)<commit_after>extern crate bincode;
extern crate rustc_serialize;
extern crate rpsrtsrs;
extern crate docopt;

use std::net::{TcpListener, TcpStream};
use std::io::Write;
use std::ops::Deref;
use std::sync::{Mutex,Arc};
use std::thread;
use std::time::Duration;

use docopt::Docopt;

use rpsrtsrs::state::{World, Player, Unit};
use rpsrtsrs::network::{Message};

use bincode::SizeLimit;
use bincode::rustc_serialize::{decode_from, encode};
use bincode::rustc_serialize::DecodingResult;

type SafeWorldState = Arc<Mutex<World>>;

fn handle_client(mut stream: TcpStream, world: SafeWorldState) {

    // handle client hello
    let client_message: DecodingResult<Message> = decode_from(&mut stream, SizeLimit::Bounded(128));
    match client_message {
        Ok(message) => {
            match message {
                Message::ClientHello => {
                    let mut world_lock = world.lock().unwrap();
                    let id = world_lock.game.players.last().map_or(0, |player| player.id+1);
                    // create new player for the newly connected client
                    let mut player = Player::new(id);
                    player.units.push(Unit::new([ 50, 50]));
                    player.units.push(Unit::new([ 50,100]));
                    player.units.push(Unit::new([100, 50]));
                    player.units.push(Unit::new([100,100]));
                    world_lock.game.players.push(player);

                    let encoded: Vec<u8> = encode(&Message::ServerHello(
                            id, world_lock.clone()), SizeLimit::Infinite).unwrap();
                    stream.write(&encoded).unwrap();
                },
                Message::ClientReconnect(id) => {
                    let world_lock = world.lock().unwrap();

                    match world_lock.game.players.iter().find(|player|player.id==id) {
                        Some(_) => {
                            println!("Found you :)");
                            let encoded: Vec<u8> = encode(&Message::ServerHello(
                                    id, world_lock.clone()), SizeLimit::Infinite).unwrap();
                            stream.write(&encoded).unwrap();
                        },
                        None => {
                            println!("Reconnect to id {} not possible", id);
                            let encoded: Vec<u8> = encode(&Message::Error, SizeLimit::Infinite).unwrap();
                            stream.write(&encoded).unwrap();
                            return
                        }
                    }
                },
                _ => {
                    println!("Did not receive ClientHello{:?}", message);
                    let encoded: Vec<u8> = encode(&Message::Error, SizeLimit::Infinite).unwrap();
                    stream.write(&encoded).unwrap();
                    return
                }
            }
        }
        Err(e) => {
            println!("{:?}", e);
            return
        }
    }

    // GameState loop
    loop {
        let encoded: Vec<u8> = {
            let world_lock = world.lock().unwrap();
            encode(&world_lock.game, SizeLimit::Infinite).unwrap()
        };
        match stream.write(&encoded) {
            Err(e) => {
                println!("Error: {:?}", e);
                return;
            }
            _ => thread::sleep(Duration::from_millis(1000)),
        };
    }
}

fn update_world(world: SafeWorldState) {
    loop {
        {
            let mut world_lock = world.lock().unwrap();
            for player in world_lock.game.players.iter_mut() {
                for unit in player.units.iter_mut() {
                    unit.update(500);
                    println!("{:?}", unit);
                }
            }
        }
        thread::sleep(Duration::from_millis(500));
    }
}

static USAGE: &'static str = "
Usage: server [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 8080].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
    -r ID    Reconnect with the given ID
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i;
    let port = args.flag_p;

    let tcp_listener = TcpListener::bind((host.deref(),port)).unwrap();
    println!("Start server: {:?}", tcp_listener);

    let world = Arc::new(Mutex::new(World::new(800, 600)));
    let world_clone = world.clone();
    thread::spawn(move || {
        update_world(world_clone);
    });

    for stream in tcp_listener.incoming() {
        match stream {
            Ok(stream) => {
                let world_clone = world.clone();
                println!("Spawning thread...");
                thread::spawn(move || {
                    handle_client(stream, world_clone);
                });
            }
            Err(e) => {
                println!("{:?}", e);
            }
        }
    }
    drop(tcp_listener);
}
<|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

use std::collections::VecMap;
use std::num::Int;
use std::{os, mem};

use gc_object::GCObjectRef;
use constants::{BLOCK_SIZE, LINE_SIZE, NUM_LINES_PER_BLOCK};

pub struct BlockInfo {
    mmap: os::MemoryMap,
    line_counter: VecMap<u8>,
}

impl BlockInfo {
    pub fn new(mmap: os::MemoryMap) -> BlockInfo {
        debug_assert!(mmap.len() > mem::size_of::<BlockInfo>());
        let mut block = BlockInfo {
            mmap: mmap,
            line_counter: VecMap::with_capacity(NUM_LINES_PER_BLOCK),
        };
        block.clear_line_counts();
        return block;
    }

    pub fn into_memory_map(self) -> os::MemoryMap {
        return self.mmap;
    }

    pub fn scan_block(&self, last_high_offset: u16) -> Option<(u16, u16)> {
        debug!("Scanning block {:p} for a hole", self);
        let last_high_index = last_high_offset as uint / LINE_SIZE;
        let mut low_index = NUM_LINES_PER_BLOCK - 1;
        for index in range(last_high_index + 1, NUM_LINES_PER_BLOCK) {
            if self.line_counter.get(&index).map_or(true, |c| *c == 0) {
                // +1 to skip the next line in case an object straddles lines
                low_index = index + 1;
                break;
            }
        }
        debug!("Found low index {} in block {:p}", low_index, self);
        let mut high_index = NUM_LINES_PER_BLOCK;
        for index in range(low_index + 1, NUM_LINES_PER_BLOCK) {
            if self.line_counter.get(&index).map_or(false, |c| *c != 0) {
                high_index = index;
                break;
            }
        }
        debug!("Found high index {} in block {:p}", high_index, self);
        return if low_index < (NUM_LINES_PER_BLOCK - 1) {
            Some(((low_index * LINE_SIZE) as u16,
            (high_index * LINE_SIZE - 1) as u16))
        } else {
            debug!("Found no hole in block {:p}", self);
            None
        };
    }

    pub fn offset(&mut self, offset: uint) -> GCObjectRef {
        return unsafe{ self.mmap.data().offset(offset as int) } as GCObjectRef;
    }

    fn object_to_line_num(object: GCObjectRef) -> uint {
        return (object as uint % BLOCK_SIZE) / LINE_SIZE;
    }

    fn update_line_nums(&mut self, object: GCObjectRef, increment: bool) {
        // This calculates how many lines are affected starting from a
        // LINE_SIZE aligned address. So it might not mark enough lines. But
        // that does not matter as we always skip a line in scan_block()
        let line_num = BlockInfo::object_to_line_num(object);
        let object_size = unsafe{ (*object).object_size() };
        for line in range(line_num, line_num + (object_size / LINE_SIZE) + 1) {
            match increment {
                true => {
                    self.line_counter.update(line, 1, |o, n| o + n);
                    debug!("Incremented line count for line {} to {}", line,
                           self.line_counter.get(&line).unwrap());
                },
                false => {
                    self.line_counter.update(line, 0,
                                             |o, _| Int::saturating_sub(o, 1));
                    debug!("Decremented line count for line {} to {}", line,
                           self.line_counter.get(&line).unwrap());
                }
            }
        }
    }

    pub fn increment_lines(&mut self, object: GCObjectRef) {
        self.update_line_nums(object, true);
    }

    pub fn decrement_lines(&mut self, object: GCObjectRef) {
        self.update_line_nums(object, false);
    }

    pub fn clear_line_counts(&mut self) {
        for index in range(0, NUM_LINES_PER_BLOCK) {
            self.line_counter.insert(index, 0);
        }
    }

    pub fn is_empty(&self) -> bool {
        return self.line_counter.values().all(|v| *v == 0);
    }

    pub fn count_holes_and_marked_lines(&self) -> (u8, u8) {
        let (holes, _, marked_lines) = self.line_counter.values()
            .fold((0, false, 0), |(holes, in_hole, marked_lines), &elem|
                  match (in_hole, elem) {
                    (true, 0) => (holes, true, marked_lines),
                    (true, _) => (holes, false, marked_lines + 1),
                    (false, 0) => (holes + 1, true, marked_lines),
                    (false, _) => (holes, false, marked_lines + 1),
                  });
        return (holes, marked_lines);
    }
}

<commit_msg>Reorganize methods for BlockInfo<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

use std::collections::VecMap;
use std::num::Int;
use std::{os, mem};

use gc_object::GCObjectRef;
use constants::{BLOCK_SIZE, LINE_SIZE, NUM_LINES_PER_BLOCK};

pub struct BlockInfo {
    mmap: os::MemoryMap,
    line_counter: VecMap<u8>,
}

impl BlockInfo {
    pub fn new(mmap: os::MemoryMap) -> BlockInfo {
        debug_assert!(mmap.len() > mem::size_of::<BlockInfo>());
        let mut block = BlockInfo {
            mmap: mmap,
            line_counter: VecMap::with_capacity(NUM_LINES_PER_BLOCK),
        };
        block.clear_line_counts();
        return block;
    }

    pub fn into_memory_map(self) -> os::MemoryMap {
        return self.mmap;
    }

    pub fn increment_lines(&mut self, object: GCObjectRef) {
        self.update_line_nums(object, true);
    }

    pub fn decrement_lines(&mut self, object: GCObjectRef) {
        self.update_line_nums(object, false);
    }

    pub fn clear_line_counts(&mut self) {
        for index in range(0, NUM_LINES_PER_BLOCK) {
            self.line_counter.insert(index, 0);
        }
    }

    pub fn is_empty(&self) -> bool {
        return self.line_counter.values().all(|v| *v == 0);
    }

    pub fn offset(&self, offset: uint) -> GCObjectRef {
        return unsafe{ self.mmap.data().offset(offset as int) } as GCObjectRef;
    }

    pub fn scan_block(&self, last_high_offset: u16) -> Option<(u16, u16)> {
        debug!("Scanning block {:p} for a hole", self);
        let last_high_index = last_high_offset as uint / LINE_SIZE;
        let mut low_index = NUM_LINES_PER_BLOCK - 1;
        for index in range(last_high_index + 1, NUM_LINES_PER_BLOCK) {
            if self.line_counter.get(&index).map_or(true, |c| *c == 0) {
                // +1 to skip the next line in case an object straddles lines
                low_index = index + 1;
                break;
            }
        }
        debug!("Found low index {} in block {:p}", low_index, self);
        let mut high_index = NUM_LINES_PER_BLOCK;
        for index in range(low_index + 1, NUM_LINES_PER_BLOCK) {
            if self.line_counter.get(&index).map_or(false, |c| *c != 0) {
                high_index = index;
                break;
            }
        }
        debug!("Found high index {} in block {:p}", high_index, self);
        return if low_index < (NUM_LINES_PER_BLOCK - 1) {
            Some(((low_index * LINE_SIZE) as u16,
            (high_index * LINE_SIZE - 1) as u16))
        } else {
            debug!("Found no hole in block {:p}", self);
            None
        };
    }

    pub fn count_holes_and_marked_lines(&self) -> (u8, u8) {
        let (holes, _, marked_lines) = self.line_counter.values()
            .fold((0, false, 0), |(holes, in_hole, marked_lines), &elem|
                  match (in_hole, elem) {
                    (true, 0) => (holes, true, marked_lines),
                    (true, _) => (holes, false, marked_lines + 1),
                    (false, 0) => (holes + 1, true, marked_lines),
                    (false, _) => (holes, false, marked_lines + 1),
                  });
        return (holes, marked_lines);
    }
}

impl BlockInfo {
    fn object_to_line_num(object: GCObjectRef) -> uint {
        return (object as uint % BLOCK_SIZE) / LINE_SIZE;
    }

    fn update_line_nums(&mut self, object: GCObjectRef, increment: bool) {
        // This calculates how many lines are affected starting from a
        // LINE_SIZE aligned address. So it might not mark enough lines. But
        // that does not matter as we always skip a line in scan_block()
        let line_num = BlockInfo::object_to_line_num(object);
        let object_size = unsafe{ (*object).object_size() };
        for line in range(line_num, line_num + (object_size / LINE_SIZE) + 1) {
            match increment {
                true => {
                    self.line_counter.update(line, 1, |o, n| o + n);
                    debug!("Incremented line count for line {} to {}", line,
                           self.line_counter.get(&line).unwrap());
                },
                false => {
                    self.line_counter.update(line, 0,
                                             |o, _| Int::saturating_sub(o, 1));
                    debug!("Decremented line count for line {} to {}", line,
                           self.line_counter.get(&line).unwrap());
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![allow(missing_copy_implementations)]

use cass_types::cass_bool_t;
use cass_types::cass_double_t;
use cass_types::cass_float_t;
use cass_types::cass_size_t;
use cass_types::cass_int32_t;
use cass_types::cass_int64_t;

use cass_error::CassError;
use cass_bytes::CassBytes;
use cass_inet::CassInet;
use cass_uuid::CassUuid;
use cass_string::CassString;
use cass_decimal::CassDecimal;

pub enum CassValue { }

#[repr(C)]
#[derive(Show,Copy)]
pub enum CassValueType {
    UNKNOWN = 65535is,
    CUSTOM = 0,
    ASCII = 1,
    BIGINT = 2,
    BLOB = 3,
    BOOLEAN = 4,
    COUNTER = 5,
    DECIMAL = 6,
    DOUBLE = 7,
    FLOAT = 8,
    INT = 9,
    TEXT = 10,
    TIMESTAMP = 11,
    UUID = 12,
    VARCHAR = 13,
    VARINT = 14,
    TIMEUUID = 15,
    INET = 16,
    LIST = 32,
    MAP = 33,
    SET = 34,
}

extern "C" {
    pub fn cass_value_get_int32(value: *const CassValue, output: *mut cass_int32_t) -> CassError;
    pub fn cass_value_get_int64(value: *const CassValue, output: *mut cass_int64_t) -> CassError;
    pub fn cass_value_get_float(value: *const CassValue, output: *mut cass_float_t) -> CassError;
    pub fn cass_value_get_double(value: *const CassValue, output: *mut cass_double_t) -> CassError;
    pub fn cass_value_get_bool(value: *const CassValue, output: *mut cass_bool_t) -> CassError;
    pub fn cass_value_get_uuid(value: *const CassValue, output: *mut CassUuid) -> CassError;
    pub fn cass_value_get_inet(value: *const CassValue, output: *mut CassInet) -> CassError;
    pub fn cass_value_get_string(value: *const CassValue, output: *mut CassString) -> CassError;
    pub fn cass_value_get_bytes(value: *const CassValue, output: *mut CassBytes) -> CassError;
    pub fn cass_value_get_decimal(value: *const CassValue, output: *mut CassDecimal) -> CassError;
    pub fn cass_value_type(value: *const CassValue) -> CassValueType;
    pub fn cass_value_is_null(value: *const CassValue) -> cass_bool_t;
    pub fn cass_value_is_collection(value: *const CassValue) -> cass_bool_t;
    pub fn cass_value_item_count(collection: *const CassValue) -> cass_size_t;
    pub fn cass_value_primary_sub_type(collection: *const CassValue) -> CassValueType;
    pub fn cass_value_secondary_sub_type(collection: *const CassValue) -> CassValueType;
}
<commit_msg>partialeq attempt<commit_after>#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![allow(missing_copy_implementations)]

use cass_types::cass_bool_t;
use cass_types::cass_double_t;
use cass_types::cass_float_t;
use cass_types::cass_size_t;
use cass_types::cass_int32_t;
use cass_types::cass_int64_t;

use cass_error::CassError;
use cass_bytes::CassBytes;
use cass_inet::CassInet;
use cass_uuid::CassUuid;
use cass_string::CassString;
use cass_decimal::CassDecimal;

pub enum CassValue { }

#[repr(C)]
#[derive(Show,Copy,PartialEq)]
pub enum CassValueType {
    UNKNOWN = 65535is,
    CUSTOM = 0,
    ASCII = 1,
    BIGINT = 2,
    BLOB = 3,
    BOOLEAN = 4,
    COUNTER = 5,
    DECIMAL = 6,
    DOUBLE = 7,
    FLOAT = 8,
    INT = 9,
    TEXT = 10,
    TIMESTAMP = 11,
    UUID = 12,
    VARCHAR = 13,
    VARINT = 14,
    TIMEUUID = 15,
    INET = 16,
    LIST = 32,
    MAP = 33,
    SET = 34,
}

extern "C" {
    pub fn cass_value_get_int32(value: *const CassValue, output: *mut cass_int32_t) -> CassError;
    pub fn cass_value_get_int64(value: *const CassValue, output: *mut cass_int64_t) -> CassError;
    pub fn cass_value_get_float(value: *const CassValue, output: *mut cass_float_t) -> CassError;
    pub fn cass_value_get_double(value: *const CassValue, output: *mut cass_double_t) -> CassError;
    pub fn cass_value_get_bool(value: *const CassValue, output: *mut cass_bool_t) -> CassError;
    pub fn cass_value_get_uuid(value: *const CassValue, output: *mut CassUuid) -> CassError;
    pub fn cass_value_get_inet(value: *const CassValue, output: *mut CassInet) -> CassError;
    pub fn cass_value_get_string(value: *const CassValue, output: *mut CassString) -> CassError;
    pub fn cass_value_get_bytes(value: *const CassValue, output: *mut CassBytes) -> CassError;
    pub fn cass_value_get_decimal(value: *const CassValue, output: *mut CassDecimal) -> CassError;
    pub fn cass_value_type(value: *const CassValue) -> CassValueType;
    pub fn cass_value_is_null(value: *const CassValue) -> cass_bool_t;
    pub fn cass_value_is_collection(value: *const CassValue) -> cass_bool_t;
    pub fn cass_value_item_count(collection: *const CassValue) -> cass_size_t;
    pub fn cass_value_primary_sub_type(collection: *const CassValue) -> CassValueType;
    pub fn cass_value_secondary_sub_type(collection: *const CassValue) -> CassValueType;
}
<|endoftext|>


<commit_before>#![allow(unused_imports, unused_variables, unused_attributes, unused_mut, dead_code)]

use clap::error::{ContextKind, ContextValue, ErrorKind};
use clap::Error;
use clap::{arg, Arg, ArgMatches, Command};

use std::collections::HashMap;
use std::env;
use std::fmt::Debug;
use std::ops::Range;
use std::path::PathBuf;
use std::str::FromStr;

use crate::cfg::loader::Loader;
use crate::cfg::spec::{Nargs, Otto, Param, Params, Spec, Task, Tasks, Value};

#[macro_use]
use super::macros;
use super::error;

static OTTOFILE: &str = "./otto.yml";

fn print_type_of<T: ?Sized>(t: &T)
where
    T: Debug,
{
    println!("type={} value={:#?}", std::any::type_name::<T>(), t);
}

fn extract(item: (ContextKind, &ContextValue)) -> Option<&ContextValue> {
    let (k, v) = item;
    if k == ContextKind::InvalidArg {
        return Some(v);
    }
    None
}

pub trait GetKnownMatches {
    fn get_known_matches(&self) -> Result<(ArgMatches, Vec<String>), Error>;
    fn get_known_matches_from(&self, args: &mut Vec<String>) -> Result<(ArgMatches, Vec<String>), Error>;
}

impl<'a> GetKnownMatches for Command<'a> {
    fn get_known_matches(&self) -> Result<(ArgMatches, Vec<String>), Error> {
        let mut args: Vec<String> = env::args().collect();
        self.get_known_matches_from(&mut args)
    }
    fn get_known_matches_from(&self, args: &mut Vec<String>) -> Result<(ArgMatches, Vec<String>), Error> {
        let mut rem: Vec<String> = vec![];
        loop {
            match self.clone().try_get_matches_from(&*args) {
                Ok(matches) => {
                    return Ok((matches, rem));
                }
                Err(error) => match error.kind() {
                    ErrorKind::UnknownArgument => {
                        let items = error.context().find_map(extract);
                        match items {
                            Some(ContextValue::String(s)) => {
                                rem.push(s.to_owned());
                                args.retain(|a| a != s);
                            }
                            Some(&_) => {
                                return Err(error);
                            }
                            None => {
                                return Err(error);
                            }
                        }
                    }
                    _ => {
                        return Err(error);
                    }
                },
            }
        }
    }
}
#[derive(Debug, Default, PartialEq, Clone)]
struct PartitionedArgs {
    args: Vec<String>,
    partitions: Vec<Range<usize>>,
}
impl PartitionedArgs {
    fn new(tasknames: &[&str]) -> Self {
        let args: Vec<String> = env::args().collect();
        let mut beg = 0;
        let mut partitions = vec![];
        for (i, arg) in args.iter().skip(1).enumerate() {
            if tasknames.iter().any(|t| t == arg) {
                let end = i + 1;
                partitions.push(Range::<usize> { start: beg, end });
                beg = end;
            }
        }
        partitions.push(Range::<usize> {
            start: beg,
            end: args.len(),
        });
        Self { args, partitions }
    }
    fn partitions(&self) -> Vec<&[String]> {
        self.partitions.iter().map(|p| &self.args[p.clone()]).collect()
    }
    fn partition(&self, index: usize) -> Option<&[String]> {
        if index < self.len() {
            return Some(&self.args[self.partitions[index].clone()]);
        }
        None
    }
    fn len(&self) -> usize {
        self.partitions.len()
    }
}

#[derive(Debug, PartialEq)]
pub struct Parser {
    ottofile: String,
}

impl Default for Parser {
    fn default() -> Self {
        Self::new()
    }
}

impl Parser {
    pub fn new() -> Self {
        Self {
            ottofile: env::var("OTTOFILE").unwrap_or_else(|_| OTTOFILE.to_owned()),
        }
    }
    fn otto_seed(&self, nerfed: bool) -> Command {
        Command::new("otto")
            .disable_help_flag(nerfed)
            .disable_version_flag(nerfed)
            .arg(
                Arg::new("ottofile")
                    .takes_value(true)
                    .short('o')
                    .long("ottofile")
                    .help("override default path to ottofile"),
            )
    }

    pub fn divine_ottofile(&self) -> PathBuf {
        (match GetKnownMatches::get_known_matches(&self.otto_seed(true)) {
            Ok((matches, _)) => match matches.value_of("ottofile").map(str::to_string) {
                Some(s) => s,
                None => self.ottofile.clone(),
            },
            Err(error) => self.ottofile.clone(),
        }).into()
    }
    pub fn parse(&self) -> Vec<ArgMatches> {
        let ottofile = self.divine_ottofile();
        if ottofile.exists() {
            let loader = Loader::new(&ottofile);
            let spec = loader.load().unwrap();
            let task_names = spec.otto.task_names();
            let mut commands = HashMap::<&str, Command>::new();
            for task_name in task_names.clone() {
                let task = &spec.otto.tasks[task_name];
                let command = Parser::build_command(task.name.clone(), task.params.clone());
                commands.insert(task_name, command);
            }
            let pa = PartitionedArgs::new(&task_names.clone());
        } else {
            let after_help = format!("ottofile={:?} does not exist!", ottofile);
            let otto = self
                .otto_seed(false)
                .arg_required_else_help(true)
                .after_help(after_help.as_str());
            let matches = otto.get_matches_from(vec!["--help"]);
        }
        vec![]
    }
    fn task_to_command(task: &Task) -> Command {
        let mut command = Command::new(&task.name);
        for param in task.params.values() {
            print_type_of(&param);
            command = command.arg(Parser::param_to_arg(param));
        }
        command
    }
    fn build_command(name: String, params: Params) -> Command<'static> {
        let mut command = Command::new(&name);
        command
    }
    fn param_to_arg(param: &Param) -> Arg {
        let mut arg = Arg::new(&*param.name);
        if let Some(short) = param.short {
            arg = arg.short(short);
        }
        if let Some(long) = &param.long {
            arg = arg.long(long);
        }
        arg
    }
}
<commit_msg>rewrote some parts with the help of copilot<commit_after>#![allow(unused_imports, unused_variables, unused_attributes, unused_mut, dead_code)]

use clap::error::{ContextKind, ContextValue, ErrorKind};
use clap::Error;
use clap::{arg, Arg, ArgMatches, Command};

use std::collections::HashMap;
use std::env;
use std::fmt::Debug;
use std::ops::Range;
use std::path::PathBuf;
use std::str::FromStr;

use crate::cfg::loader::Loader;
use crate::cfg::spec::{Nargs, Otto, Param, Params, Spec, Task, Tasks, Value};

#[macro_use]
use super::macros;
use super::error;

static OTTOFILE: &str = "./otto.yml";

fn print_type_of<T: ?Sized>(t: &T)
where
    T: Debug,
{
    println!("type={} value={:#?}", std::any::type_name::<T>(), t);
}

fn extract(item: (ContextKind, &ContextValue)) -> Option<&ContextValue> {
    let (k, v) = item;
    if k == ContextKind::InvalidArg {
        return Some(v);
    }
    None
}

pub trait GetKnownMatches {
    fn get_known_matches(&self) -> Result<(ArgMatches, Vec<String>), Error>;
    fn get_known_matches_from(&self, args: &mut Vec<String>) -> Result<(ArgMatches, Vec<String>), Error>;
}

impl<'a> GetKnownMatches for Command<'a> {
    fn get_known_matches(&self) -> Result<(ArgMatches, Vec<String>), Error> {
        let mut args: Vec<String> = env::args().collect();
        self.get_known_matches_from(&mut args)
    }
    fn get_known_matches_from(&self, args: &mut Vec<String>) -> Result<(ArgMatches, Vec<String>), Error> {
        let mut rem: Vec<String> = vec![];
        loop {
            match self.clone().try_get_matches_from(&*args) {
                Ok(matches) => {
                    return Ok((matches, rem));
                }
                Err(error) => match error.kind() {
                    ErrorKind::UnknownArgument => {
                        let items = error.context().find_map(extract);
                        match items {
                            Some(ContextValue::String(s)) => {
                                rem.push(s.to_owned());
                                args.retain(|a| a != s);
                            }
                            Some(&_) => {
                                return Err(error);
                            }
                            None => {
                                return Err(error);
                            }
                        }
                    }
                    _ => {
                        return Err(error);
                    }
                },
            }
        }
    }
}

/*
#[derive(Debug, Default, PartialEq, Clone)]
struct Partition {
    name: String,
    args: Vec<String>,
}
impl Partition {
    fn new(name: &str, args: &[String]) -> Self {
        Self {
            name: name.to_owned(),
            args: args.to_vec(),
        }
    }
    fn partition(tasknames: &[&str]) -> Vec<Partition> {
        let args: Vec<String> = env::args().collect();
        let mut partitions = vec![];
        let mut beg: usize = 0;
        for (i, arg) in args.iter().skip(1).enumerate() {
            if tasknames.iter().any(|t: &&str| t == arg) {
                let end = i + 1;
                partitions.push(Partition::new(&args[beg..end].join(" "), &args[beg..end]));
                beg = end;
            }
        }
        partitions.push(Partition::new("default", &args[beg..]));
        partitions
    }
}
*/

fn partition(task_names: &[&str]) -> HashMap<String, Vec<String>> {
    let args: Vec<String> = env::args().collect();
    let mut partitions = HashMap::new();
    let mut beg: usize = 0;
    for (i, arg) in args.iter().skip(1).enumerate() {
        if task_names.iter().any(|t: &&str| t == arg) {
            let end = i + 1;
            partitions.insert(arg.to_owned(), args[beg..end].to_vec());
            beg = end;
        }
    }
    partitions.insert("default".to_owned(), args[beg..].to_vec());
    partitions
}

#[derive(Debug, PartialEq)]
pub struct Parser {
    ottofile: String,
}

impl Default for Parser {
    fn default() -> Self {
        Self::new()
    }
}

impl Parser {
    pub fn new() -> Self {
        Self {
            ottofile: env::var("OTTOFILE").unwrap_or_else(|_| OTTOFILE.to_owned()),
        }
    }
    fn otto_seed(&self, nerfed: bool) -> Command {
        Command::new("otto")
            .disable_help_flag(nerfed)
            .disable_version_flag(nerfed)
            .arg(
                Arg::new("ottofile")
                    .takes_value(true)
                    .short('o')
                    .long("ottofile")
                    .help("override default path to ottofile"),
            )
    }
    pub fn divine_ottofile(&self) -> PathBuf {
        (match GetKnownMatches::get_known_matches(&self.otto_seed(true)) {
            Ok((matches, _)) => match matches.value_of("ottofile").map(str::to_string) {
                Some(s) => s,
                None => self.ottofile.clone(),
            },
            Err(error) => self.ottofile.clone(),
        }).into()
    }
    pub fn parse(&self) -> Vec<ArgMatches> {
        let ottofile = self.divine_ottofile();
        let mut matches_vec: Vec<ArgMatches> = vec![];
        if ottofile.exists() {
            let loader = Loader::new(&ottofile);
            let spec = loader.load().unwrap();
            let task_names = spec.otto.task_names();
            let partitions = partition(&task_names);
            for (name, args) in partitions {
                let task = &spec.otto.tasks[&name];
                let command = Parser::task_to_command(task);
                let mut args = args.clone();
                args.insert(0, name.to_owned());
                let matches = command.clone().try_get_matches_from(&args).unwrap();
                matches_vec.push(matches);
            }
        } else {
            let after_help = format!("ottofile={:?} does not exist!", ottofile);
            let otto = self
                .otto_seed(false)
                .arg_required_else_help(true)
                .after_help(after_help.as_str());
            let matches = otto.get_matches_from(vec!["--help"]);
            matches_vec.push(matches);
        }
        matches_vec
    }
    fn task_to_command(task: &Task) -> Command {
        let mut command = Command::new(&task.name);
        for param in task.params.values() {
            command = command.arg(Parser::param_to_arg(param));
        }
        command
    }
    fn param_to_arg(param: &Param) -> Arg {
        let mut arg = Arg::new(&*param.name);
        if let Some(short) = param.short {
            arg = arg.short(short);
        }
        if let Some(long) = &param.long {
            arg = arg.long(long.as_str());
        }
        arg
    }
}
<|endoftext|>