gamozolabs / safecast

Safe casting in Rust!
MIT License
7 stars 5 forks source link

safecast

An attempt to make a procedural macro to support safe casting in Rust.

Goals

This library is designed to allow for copying raw underlying data between different types in Rust. This is helpful for handling things like binary files or network protocols. Using this library you are able to safely create structures and cast/copy between them.

Example usage

In Cargo.toml:

[dependencies]
safecast = { path = "../path/to/safecast" }

Example program:

use safecast::Safecast;

#[derive(Safecast, Debug)]
#[repr(C)]
struct PacketData {
    data:     u64,
    sequence: u64,
    flags:    u32,
    _padding: u32,
}

fn main() {
    let packet = [0x41u8; 0x18];

    let val: PacketData = packet.cast_copy();

    print!("Packet data is {:#x?}\n", val);
}

Output:

Packet data is PacketData {
    data: 0x4141414141414141,
    sequence: 0x4141414141414141,
    flags: 0x41414141,
    _padding: 0x41414141
}

Safety

This casting/copying is safe given the following:

Interface

Safecast::cast_copy_into<T: Safecast + ?Sized>(&self, dest: &mut T)

This routine allows the casting from an existing structure to another type given the other type also implemented Safecast. This method is the one used when T is ?Sized, allowing for us to cast into things like slices/Vecs. This is the core implementation and is used by cast().

This method will panic unless both self and T are equal in size (in bytes).

Safecast::cast_copy<T: Safecast>(&self) -> T

Creates an uninitialized value of type T, and calls cast_into on self to cast it into T. Returns the new value.

This method will panic unless both self and T are equal in size (in bytes).

Safecast::cast<T: Safecast>(&self) -> &[T]

Casts Self to a slice of Ts, where Self is evenly divisible by T.

Safecast::cast_mut<T: Safecast>(&mut self) -> &mut [T]

Casts Self to a mutable slice of Ts, where Self is evenly divisible by T.

Endianness

I'm not sure if it matches Rust's definition, however I think it is fine for the endianness to be up to the user to handle. There is no safety violation by having an unexpected endian swap, thus I'm okay with this not handling endian swaps for you. It is up to the user to manually swap fields as they use them.