Creazione di campi di unione / sovrapposizione sicuri nelle strutture
In C ++, posso creare strutture come queste:
union Vector4
{
struct { float x, y, z, w; };
float data[4];
};
così posso accedere facilmente ai dati come campi o come array contiguo. In alternativa, posso semplicemente creare un puntatore al primo campo x
e leggere dal puntatore come un array contiguo.
So che ci sono enumerazioni, ma non posso pagare le spese generali aggiuntive. So anche che posso creare unioni in Rust, ma mi richiedono di sporcare il mio codice unsafe
ovunque io acceda a loro. Cosa che sento di non doverlo fare poiché il codice non è pericoloso poiché i dati sottostanti sono sempre rappresentati come float (e ho bisogno del layout C in #[repr(C)]
modo che il compilatore non generi l'ordine dei campi).
Come lo implementerei in Rust in modo da poter accedere ai campi per nome ma anche avere un accesso facile e sicuro alla memoria contigua dell'intera struttura? Se questo non è possibile, esiste un modo per prendere in sicurezza una fetta di una struttura?
Risposte
Non esiste un'unione sicura. Personalmente, direi che la trasmutazione tra array di dimensioni fisse di tipi interi dovrebbe essere considerata sicura, ma al momento non ci sono eccezioni.
Detto questo, ecco il mio totalmente al 100% non un sindacato Vector4
. Come puoi vedere, Deref
funziona per nascondere il codice non sicuro e lo fa in modo da poterlo trattare Vector4
come uno struct o un array in base al contesto in cui viene utilizzato. Anche la trasmutazione non è l'ideale, ma mi sento come se potessi giustificarlo in questo caso. Se scegli di fare qualcosa di simile, potresti anche voler implementare 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]
}