Accès protégé aux champs
On souhaite, pour des buts pédagogiques plus qu'utilitaires, implémenter une macro de type derive Opaque
. Celle-ci permet de définir des accesseurs sécurisés pour les champs concernés d'une structure :
#[derive(Opaque)]
struct SecureSettings {
#[key] secret_key: u64,
regular_field: String,
#[opaque] protected_field: String,
#[opaque] other_protected_field: u32,
}
Notre macro va ajouter automatiquement un accesseur aux champs marqués #[opaque]
. Cet accesseur prendra un paramètre key
de type référence sur le type du champ marqué avec l'attribut #[key]
et renverra une Option
contenant le champ demandé uniquement si la clé passée est correcte. Le code généré ressemblera au suivant :
impl SecureSettings {
fn get_protected_field(&self, key: &u64) -> Option<&String> {
(key == &self.key).then(|| &self.protected_field)
}
fn get_other_protected_field(&self, key: &u64) -> Option<&u32> {
(key == &self.key).then(|| &self.other_protected_field)
}
}
Implémentation
-
Écrivez dans le crate
macros
le squelette de la macro de type derive pourOpaque
. Cette macro prendra en attributs supplémentaireskey
etopaque
qui serviront à qualiier des champs. Pour l'instant, ne renvoyez rien d'utile. -
Vérifiez que l'argument passé à la macro est bien une structure contenant des champs nommés et indiquez un message d'erreur approprié si ce n'est pas le cas.
-
Identifiez le champ marqué avec
#[key]
qui doit être unique ainsi que les champs marqués avec#[opaque]
. Le champ contenant la clé ne peut pas être également#[opaque]
. -
Après avoir mis dans des vecteurs le nom de chaque champ opaque, son type et l'identifiant à utiliser pour son accesseur, générez le code. Vous aurez également besoin d'avoir dans des variables accessibles lors de l'expansion le nom et le type du champ contenant la clé.
-
Testez, sans oublier les tests avec
trybuild
pour vérifier la précision des messages d'erreur.