[−][src]Module typic::safe
Guidance and tools for safe transmutation.
A sound transmutation is safe only if it also cannot violate library
invariants on types. Unless a type implements Transparent
, it is
assumed to have library-defined invariants on its fields.
Why is safety different than soundness?
Consider the type Constrained
, which enforces a validity constraint on its
fields, and the type Unconstrained
(which has no internal validity
constraints):
#[typic::repr(C)] pub struct Constrained { wizz: i8, bang: u8, } impl Constrained { /// the sum of `wizz` and `bang` must be greater than or equal to zero. pub fn new(wizz: i8, bang: u8) -> Self { assert!((wizz as i16) / (bang as i16) >= 0); Constrained { wizz, bang } } pub fn something_dangerous(&self) { unsafe { // do something that's only safe if `wizz + bang >= 0` } } } #[typic::repr(C)] pub struct Unconstrained { pub wizz: u8, pub bang: i8, }
It is sound to transmute in instance of Unconstrained
into
Constrained
:
use typic::docs::prelude::*; let _ : Constrained = unsafe { transmute_sound(Unconstrained::default()) };
...but it isn't safe! The transmute_sound
function creates an instance
of Bar
without calling its new
constructor, thereby bypassing the
safety check which ensures something_dangerous
does not violate Rust's
memory model. The compiler will reject our program if we try to safely
transmute Unconstrained
to Constrained
:
let unconstrained = Unconstrained::default(); let _ : Constrained = unconstrained.transmute_into(); // ^^^^^^^^^^^^^^ // the trait `Transparent` is not // implemented for `Constrained`
Indicating that a transmutation is safe
The Transparent
trait is used to indicate that a compound type does not
place any additional validity restrictions on its fields.
This trait can be implemented manually:
#[typic::repr(C)] pub struct Unconstrained { wizz: u8, bang: i8, } unsafe impl Transparent for Unconstrained {} let _ : Unconstrained = u16::default().transmute_into();
Or, automatically, by marking the fields pub
:
#[typic::repr(C)] pub struct Unconstrained { pub wizz: u8, pub bang: i8, } let _ : Unconstrained = u16::default().transmute_into();
If the fields are marked pub
, the type cannot rely on any internal
validity requirements, as users of the type are free to manipulate its
fields via the .
operator.
Safely transmuting references
When safely transmuting owned values, only the destination must be
Transparent
:
let _ : Unconstrained = Constrained::default().transmute_into();
When safely transmuting references, both the source and destination types
must be Transparent
:
let mut x = Constrained::default(); { let y : &mut Unconstrained = (&mut x).transmute_into(); // ^^^^^^^^^^^^^^ // the trait `Transparent` is not // implemented for `Constrained` let z : u8 = -100i8.transmute_into(); y.wizz = z; } x.something_dangerous(); /// Ack! `x.wizz + x.bang` is -100!
Traits
TransmuteFrom | A safe and sound value-to-value conversion.
The opposite of |
TransmuteInto | A safe and sound value-to-value conversion.
The opposite of |
Functions
transmute_safe | A safe and sound value-to-value conversion. |