Crear campos de unión / superposición seguros en estructuras
En C ++, puedo crear estructuras como estas:
union Vector4
{
struct { float x, y, z, w; };
float data[4];
};
para que pueda acceder fácilmente a los datos como campos o como una matriz contigua. Alternativamente, puedo simplemente crear un puntero al primer campo x
y leer desde el puntero como una matriz contigua.
Sé que hay enumeraciones, pero no puedo pagar los gastos generales adicionales. También sé que puedo crear sindicatos en Rust, pero me exigen que ensucie mi código unsafe
dondequiera que acceda a ellos. Lo cual creo que no debería tener que hacerlo ya que el código no es inseguro ya que los datos subyacentes siempre se representan como flotantes (y necesito el diseño C #[repr(C)]
para que el compilador no arroje el orden de los campos).
¿Cómo implementaría esto en Rust para poder acceder a los campos por nombre pero también tener acceso fácil y seguro a la memoria contigua de toda la estructura? Si esto no es posible, ¿hay alguna manera de que pueda tomar con seguridad una porción de una estructura?
Respuestas
No existe una unión segura. Personalmente, diría que la transmutación entre matrices de tipos enteros de tamaño fijo debería considerarse segura, pero por el momento no hay excepciones.
Dicho esto, aquí está mi totalmente 100% no un sindicato Vector4
. Como puede ver, Deref
funciona para ocultar el código inseguro y lo hace para que pueda tratarlo Vector4
como una estructura o una matriz en función del contexto en el que se usa. La transmutación tampoco es ideal, pero siento que puedo justificarlo en este caso. Si elige hacer algo como esto, es posible que también desee implementarlo 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]
}