spru-bevy 0.1.0

bevy plugins for the spru strategy and digital board game framework.
Documentation
use std::collections::VecDeque;

use bevy::prelude;
use derive_where::derive_where;

#[derive(Debug, prelude::Component)]
#[require(FromClient<Server>, ToClient<Server>, FromUser<Server>, PendingClients<Server>)]
pub struct Runner<Server: super::ServerSSS> {
    pub(crate) server: Server,
}

impl<Server: super::ServerSSS> Runner<Server> {
    pub(crate) fn new(server: Server) -> Self {
        Self { server }
    }

    pub fn save(&self) -> Result<spru::server::Save<Server>, spru::server::error::SaveError>
    where
        Server::PlayerInit: Clone,
        Server::Reaction: Clone,
    {
        self.server.save()
    }

    pub fn storage(
        &self,
    ) -> &spru::item::storage::Canonical<<Server::State as tagset::TagSet>::Repr, Server::State>
    {
        self.server.storage()
    }
}

#[derive_where(Debug; spru::common::signal::ToServer<Server::Common>)]
#[derive_where(Default)]
#[derive(prelude::Component)]
pub struct FromClient<Server: super::ServerSSS> {
    queues: Vec<(
        spru::player::Id,
        VecDeque<spru::common::signal::ToServer<Server::Common>>,
    )>,
}

impl<Server: super::ServerSSS> FromClient<Server> {
    pub fn len(&self) -> usize {
        self.queues.len()
    }

    pub fn is_empty(&self) -> bool {
        for (_, queue) in &self.queues {
            if !queue.is_empty() {
                return false;
            }
        }
        true
    }

    pub fn enqueue(
        &mut self,
        client_id: spru::player::Id,
        signal: spru::common::signal::ToServer<Server::Common>,
    ) {
        get_queue_mut(client_id, &mut self.queues).push_back(signal);
    }

    pub(crate) fn dequeue_any(
        &mut self,
    ) -> Option<(
        spru::player::Id,
        spru::common::signal::ToServer<Server::Common>,
    )> {
        for (client_id, queue) in &mut self.queues {
            if let Some(signal) = queue.pop_front() {
                return Some((*client_id, signal));
            }
        }
        None
    }
}

#[derive_where(Debug; spru::common::signal::ToClient<Server::Common>)]
#[derive_where(Default)]
#[derive(prelude::Component)]
pub struct ToClient<Server: super::ServerSSS> {
    queues: Vec<(
        spru::player::Id,
        VecDeque<spru::common::signal::ToClient<Server::Common>>,
    )>,
}

impl<Server: super::ServerSSS> ToClient<Server> {
    pub fn len(&self) -> usize {
        self.queues.len()
    }

    pub fn is_empty(&self) -> bool {
        for (_, queue) in &self.queues {
            if !queue.is_empty() {
                return false;
            }
        }
        true
    }

    pub(crate) fn enqueue(
        &mut self,
        client_id: spru::player::Id,
        signal: spru::common::signal::ToClient<Server::Common>,
    ) {
        get_queue_mut(client_id, &mut self.queues).push_back(signal);
    }

    pub fn dequeue(
        &mut self,
        client_id: spru::player::Id,
    ) -> Option<spru::common::signal::ToClient<Server::Common>> {
        get_queue_mut(client_id, &mut self.queues).pop_front()
    }

    pub fn dequeue_any(
        &mut self,
    ) -> Option<(
        spru::player::Id,
        spru::common::signal::ToClient<Server::Common>,
    )> {
        for (client_id, queue) in &mut self.queues {
            if let Some(signal) = queue.pop_front() {
                return Some((*client_id, signal));
            }
        }
        None
    }
}

fn get_queue_mut<T>(
    player_id: spru::player::Id,
    queues: &mut Vec<(spru::player::Id, VecDeque<T>)>,
) -> &mut VecDeque<T> {
    let mut index = None;
    for (i, (queue_player_id, _queue)) in queues.iter_mut().enumerate() {
        if player_id == *queue_player_id {
            index = Some(i);
            break;
        }
    }

    let index = match index {
        Some(index) => index,
        None => {
            queues.push((player_id, VecDeque::new()));
            queues.len() - 1
        }
    };

    &mut queues[index].1
}

#[derive_where(Default; )]
#[derive_where(Debug; super::PendingClient<Server::Common>)]
#[derive(prelude::Component)]
pub struct PendingClients<Server: super::ServerSSS> {
    queue: VecDeque<super::PendingClient<Server::Common>>,
}

impl<Server: super::ServerSSS> PendingClients<Server> {
    pub fn len(&self) -> usize {
        self.queue.len()
    }

    pub fn is_empty(&self) -> bool {
        self.queue.is_empty()
    }

    pub(crate) fn enqueue(&mut self, pending_client: super::PendingClient<Server::Common>) {
        self.queue.push_back(pending_client);
    }

    pub fn dequeue(&mut self) -> Option<super::PendingClient<Server::Common>> {
        self.queue.pop_front()
    }
}

#[derive_where(Debug; UserInput<Server>)]
#[derive_where(Default)]
#[derive(prelude::Component)]
pub struct FromUser<Server: super::ServerSSS> {
    queue: VecDeque<UserInput<Server>>,
}

impl<Server: super::ServerSSS> FromUser<Server> {
    pub fn len(&self) -> usize {
        self.queue.len()
    }

    pub fn is_empty(&self) -> bool {
        self.queue.is_empty()
    }

    pub fn add_player(&mut self, user_init_in: <Server::PlayerInit as spru::player::Init>::In) {
        self.queue.push_back(UserInput::AddPlayer(user_init_in));
    }

    pub fn manual_trigger(&mut self, trigger: <Server::Reaction as spru::Reaction>::Trigger) {
        self.queue.push_back(UserInput::ManualTrigger(trigger));
    }

    pub(crate) fn dequeue(&mut self) -> Option<UserInput<Server>> {
        self.queue.pop_front()
    }
}

#[derive_where(Debug;
    <Server::PlayerInit as spru::player::Init>::In,
    <Server::Reaction as spru::Reaction>::Trigger,
)]
pub(crate) enum UserInput<Server: super::ServerSSS> {
    AddPlayer(<Server::PlayerInit as spru::player::Init>::In),
    ManualTrigger(<Server::Reaction as spru::Reaction>::Trigger),
}