[][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:

This example deliberately fails to compile
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:

This example deliberately fails to compile
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.

TransmuteInto

A safe and sound value-to-value conversion. The opposite of TransmuteFrom.

Functions

transmute_safe

A safe and sound value-to-value conversion.