#![no_std] #![allow(warnings)] extern crate alloc; use core::result::Result; use alloc::{boxed::Box,collections::VecDeque, vec::Vec}; use core::ops::{Deref, DerefMut}; /// Gestionnaire de closure
/// Un ensemble de méthodes est inclus pour gérer le VecDeque de closures. /// Il est préférable de recourir à celles-ci pour limiter les extensions de capacité /// et éviter tout risque d'accès concurentiel à une même closure. pub struct Manager{ list:VecDeque } /// Accès immédiat à l'unique propriété impl Deref for Manager{ type Target = VecDeque; fn deref(&self) -> &Self::Target{ &self.list } } impl DerefMut for Manager{ fn deref_mut(&mut self) -> &mut Self::Target { &mut self.list } } impl Manager{ /// Le Manager requiert une taille lors de sa construction pour définir une capacité initiale. pub fn new(cap:usize)->Manager{ return Manager { list: VecDeque::with_capacity(cap) } } /// Ajout d'un Slot
/// La méthode retourne un numéro d'index. pub fn add(&mut self,func:Slot)->usize{ let mut n = -1; for (id,f) in self.list.iter_mut().enumerate(){ if f.used == Status::Used || f.used == Status::Empty{ n = id as i32; break; } } if n != -1{ self.list[n as usize] = func; return n as usize } else{ self.list.push_back(func); return (self.list.len()-1) as usize } } /// Libération d'un emplacement, ce dernier passe en Empty et pourra être utilisé pour insérer /// une autre closure. pub fn rem(&mut self,id:usize){ self.list[id].closure = Box::new(||{}); self.list[id].used =Status::Empty; } /// Passage d'un status en Pending (Prêt à l'emploi avec exec). pub fn reload(&mut self,id:usize){ self.list[id].used = Status::Pending; } pub fn reload_all(&mut self){ for f in self.list.iter_mut(){ f.used = Status::Pending; } } /// Appel à exécution d'une closure
/// Une closure est utilisable une seule fois mais peut être remise en utilisation via la méthode reload. /// Un booléen est renvoyé pour préciser si l'exécution a été initié, un false = Pas de closure ou une closure en cours d'usage. /// L'implémentation d'exec a pour but de s'assurer qu'aucun accès concurrentiel ne soit effectif sur du travail Async/Multi-thread. pub fn exec(&mut self,id:usize)->bool{ if self.list[id].used != Status::Busy && self.list[id].used != Status::Empty{ self.list[id].used = Status::Busy; (self.list[id])(); self.list[id].used = Status::Used; return true } return false } /// Renvoi un vecteur d'index si la méthode rencontre des problèmes. pub fn exec_all(&mut self)->Result<(),Vec>{ let mut errs:Vec = Vec::new(); for (id,f) in self.list.iter_mut().enumerate(){ if f.used == Status::Busy || f.used == Status::Empty{ errs.push(id); continue; } f.used = Status::Busy; (f)(); f.used = Status::Used; } if errs.len() != 0{ return Err(errs) } return Ok(()) } } /// Ensemble des status attribuables sur un Slot
/// Un Slot arrive en Pending, passe en Busy durant tout usage et termine en Used. /// La variante Empty est utilisé pour libérer sans qu'aucun appel n'ait été fait. #[derive(PartialEq,Debug)] pub enum Status{ Pending, Busy, Used, Empty } /// Le Slot correspond à une closure en attente d'exécution
/// Chaque Slot dispose d'un Status via l'index used et d'un trait Deref pour un accès immédiat. /// Un Slot peut être exécuté manuellement selon la méthode suivante => (Slot)() pub struct Slot{ closure : Box, pub used : Status } impl Deref for Slot{ type Target = Box; fn deref(&self) -> &Self::Target { &self.closure } } impl Slot{ pub fn new(func:Box)->Slot{ return Slot { closure: func, used: Status::Pending } } }