Création de champs de superposition / union sécurisés dans les structures

Aug 16 2020

En C ++, je peux créer des structures comme celles-ci:

union Vector4
{
    struct { float x, y, z, w; };
    float data[4];
};

afin que je puisse facilement accéder aux données sous forme de champs ou de tableau contigu. Sinon, je peux simplement créer un pointeur vers le premier champ xet lire à partir du pointeur comme un tableau contigu.

Je sais qu'il y a des énumérations, mais je ne peux pas payer les frais généraux supplémentaires. Je sais aussi que je peux créer des syndicats dans Rust, mais ils m'obligent à jeter mon code partout unsafeoù j'y accède. Ce que je pense que je ne devrais pas avoir à le faire car le code n'est pas dangereux car les données sous-jacentes sont toujours représentées sous forme de flottants (et j'ai besoin de la mise en page C #[repr(C)]pour que le compilateur ne contournera pas l'ordre des champs).

Comment pourrais-je implémenter cela dans Rust pour pouvoir accéder aux champs par nom, mais aussi avoir un accès facile et sûr à toute la mémoire contiguë de la structure? Si ce n'est pas possible, y a-t-il un moyen pour que je puisse prendre en toute sécurité une tranche d'une structure?

Réponses

3 Locke Aug 17 2020 at 00:08

Il n'existe pas de syndicat sûr. Personnellement, je dirais que la transmutation entre des tableaux de taille fixe de types entiers devrait être considérée comme sûre, mais pour le moment, il n'y a pas d'exceptions.

Cela étant dit, voici mon 100% pas un syndicat Vector4. Comme vous pouvez le voir, Dereffonctionne pour masquer le code non sécurisé et permet de le traiter Vector4comme une structure ou un tableau en fonction du contexte dans lequel il est utilisé. La transmutation n'est pas non plus idéale, mais j'ai l'impression de pouvoir la justifier dans ce cas. Si vous choisissez de faire quelque chose comme ça, vous voudrez peut-être également l'implémenter DerefMut.

use std::ops::Deref;

// I'm not sure if the repr(C) is needed in this case, but I added it just in case.
#[repr(C)]
pub struct Vector4<T> {
    pub x: T,
    pub y: T,
    pub z: T,
    pub w: T,
}

impl<T> Deref for Vector4<T>
where
    T: Copy + Sized,
{
    type Target = [T; 4];

    fn deref(&self) -> &Self::Target {
        use std::mem::transmute;
        unsafe { transmute(self) }
    }
}

pub fn main() {
    let a = Vector4{
        x: 37,
        y: 21,
        z: 83,
        w: 94,
    };

    println!("{:?}", &a[..]);
    // Output: [37, 21, 83, 94]
}