Ajout du code manquant
Méthodes
Voici quelques remarques supplémentaires sur les méthodes à remplir.
write_indices()
La zone dans laquelle nous pouvons écrire les données peut être segmentées en deux parties en raison du caractère circulaire du buffer. Comme on le voyait sur le schéma d'explication présent sur la page précédente, il peut y avoir une zone qui va de write_index
jusqu'à la fin du buffer suivie d'une zone qui va du début du buffer jusqu'à read_index - 1
(non compris).
La méthode write_indices()
nous retourne en premier élément les indices où on doit écrire en premier les données entrantes et en second la zone supplémentaire de début de buffer si elle existe. On pourra distinguer 4 situations, à savoir successivement read_index > write_index
, read_index == 0
, read_index == 1
ou le cas restant.
Attention à bien utiliser les bons modes pour accéder aux indices : en retournant de write_indices()
, il faut que les endroits dans lesquels on va ensuite écrire ne contiennent bien plus rien d'utile.
push_all()
En utilisant write_indices()
, nous pouvons maintenant écrire les données qui nous sont passées en paramètre dans notre buffer circulaire. À la fin de l'écriture, il faudra penser à mettre à jour write_index
en utilisant le bon mode.
pop()
Rien de particulier à dire, si ce n'est qu'il faut s'assurer d'utiliser les bons modes pour les différentes variables atomiques qu'on utilisera, à la fois pour être sûr que la valeur lue est bien visible mais aussi que la place libérée l'est avant d'annoncer qu'elle est libre.
read_indices()
Cette méthode renvoie la zone contigüe dans laquelle on peut lire des données. Étant donné qu'on utilisera cette méthode pour présenter une slice à l'utilisateur, nous ne sommes pas intéressés pour l'instant par une seconde zone en début de buffer car ces zones n'étant pas contigües nous ne les présenterons pas en une seule *slice. On n'aura donc que deux cas à considérer. Attention là aussi aux modes, il faut avoir la garantie que les données écrites dans cette zone seront visible dès lors qu'on retournera de cette fonction.
mark_read()
Cette méthode marque comme lues les premières entrées à lire et donc on garantit qu'elles sont contigües. On pourrait implémenter mark_read()
comme une boucle de pop()
, mais cela serait inefficace de mettre à jour read_index
à chaque élément.
Attention à bien détruire chaque élément qui est lu.
drop()
En cas de destruction du buffer, il faut s'assurer de détruire les valeurs non lues qui restent à l'intérieur.
Tests
Des tests sont fournis avec le squelette. Ils vérifieront que les fonctions de base du buffer circulaire fonctionnent comme on l'attend, mais également que les éléments sont bien détruits au bon moment (et seulement à ce moment là).
On pourra remarquer dans le test tests/drop.rs
l'utilisation du crate serial_test
. Celui-ci fournit un nouvel attribut #[serial]
qui permet de sérialiser les tests qui l'utilisent. Cela est nécessaire car nous utilisons un compteur d'instances global et si les tests tournaient en parallèle nous ne pourrions pas vérifier de manière cohérente que le nombre d'instances vivantes à un moment donné correspond bien à ce que nous prévoyons.