Skip to main content

SplitAt

Trait SplitAt 

Source
pub unsafe trait SplitAt: KnownLayout<PointerMetadata = usize> {
    type Elem;

    // Provided methods
    unsafe fn split_at_unchecked(&self, l_len: usize) -> Split<&Self> { ... }
    fn split_at(&self, l_len: usize) -> Option<Split<&Self>> { ... }
    unsafe fn split_at_mut_unchecked(
        &mut self,
        l_len: usize,
    ) -> Split<&mut Self> { ... }
    fn split_at_mut(&mut self, l_len: usize) -> Option<Split<&mut Self>> { ... }
}
Expand description

Types that can be split in two.

This trait generalizes Rust’s existing support for splitting slices to support slices and slice-based dynamically-sized types (“slice DSTs”).

For a repr(C, packed) or repr(C, packed(N)) struct, the derive wraps the trailing field’s Elem in Unalign. The returned slice can therefore be accessed even when packing misaligns the original elements. Each packed struct in the trailing-field chain adds one wrapper; unpacked structs and ManuallyDrop forward their trailing type’s Elem.

§Implementation

Do not implement this trait yourself! Instead, use #[derive(SplitAt)]; e.g.:

#[derive(SplitAt, KnownLayout)]
#[repr(C)]
struct MyStruct<T: ?Sized> {
    ...,
    // `SplitAt` types must have at least one field.
    field: T,
}

This derive performs a sophisticated, compile-time safety analysis to determine whether a type is SplitAt.

A packed struct exposes its trailing elements through Unalign:

use zerocopy::{FromBytes, SplitAt, Unalign};

#[derive(FromBytes, IntoBytes, KnownLayout, SplitAt)]
#[repr(C, packed)]
struct Packet {
    tag: u8,
    words: [u16],
}

let mut bytes = [0u8; 5];
let packet = Packet::mut_from_bytes(&mut bytes[..]).unwrap();
let (left, right): (&mut Packet, &mut [Unalign<u16>]) =
    packet.split_at_mut(1).unwrap().via_into_bytes();
left.tag = 1;
right[0] = Unalign::new(0x0202);
assert_eq!(bytes, [1, 0, 0, 2, 2]);

§Safety

This trait does not convey any safety guarantees to code outside this crate.

You must not rely on the #[doc(hidden)] internals of SplitAt. Future releases of zerocopy may make backwards-breaking changes to these items, including changes that only affect soundness, which may cause code which uses those items to silently become unsound.

Required Associated Types§

Source

type Elem

The element type exposed by the split’s returned slice.

For [T], this is T. For a struct, this is the trailing field’s Elem, wrapped in Unalign if the struct is packed. Nested packed structs produce nested Unalign wrappers.

Provided Methods§

Source

unsafe fn split_at_unchecked(&self, l_len: usize) -> Split<&Self>

Unsafely splits self in two.

§Safety

The caller promises that l_len is not greater than the length of self’s trailing slice.

Source

fn split_at(&self, l_len: usize) -> Option<Split<&Self>>

Attempts to split self in two.

Returns None if l_len is greater than the length of self’s trailing slice.

§Examples
use zerocopy::{SplitAt, FromBytes};

#[derive(SplitAt, FromBytes, KnownLayout, Immutable)]
#[repr(C)]
struct Packet {
    length: u8,
    body: [u8],
}

// These bytes encode a `Packet`.
let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];

let packet = Packet::ref_from_bytes(bytes).unwrap();

assert_eq!(packet.length, 4);
assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);

// Attempt to split `packet` at `length`.
let split = packet.split_at(packet.length as usize).unwrap();

// Use the `Immutable` bound on `Packet` to prove that it's okay to
// return concurrent references to `packet` and `rest`.
let (packet, rest) = split.via_immutable();

assert_eq!(packet.length, 4);
assert_eq!(packet.body, [1, 2, 3, 4]);
assert_eq!(rest, [5, 6, 7, 8, 9]);
Source

unsafe fn split_at_mut_unchecked(&mut self, l_len: usize) -> Split<&mut Self>

Unsafely splits self in two.

§Safety

The caller promises that l_len is not greater than the length of self’s trailing slice.

§ Code Generation

See SplitAt::split_at_unchecked.

Source

fn split_at_mut(&mut self, l_len: usize) -> Option<Split<&mut Self>>

Attempts to split self in two.

Returns None if l_len is greater than the length of self’s trailing slice.

§Examples
use zerocopy::{SplitAt, FromBytes};

#[derive(SplitAt, FromBytes, KnownLayout, IntoBytes)]
#[repr(C)]
struct Packet<B: ?Sized> {
    length: u8,
    body: B,
}

// These bytes encode a `Packet`.
let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];

let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap();

assert_eq!(packet.length, 4);
assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);

{
    // Attempt to split `packet` at `length`.
    let split = packet.split_at_mut(packet.length as usize).unwrap();

    // Use the `IntoBytes` bound on `Packet` to prove that it's okay to
    // return concurrent references to `packet` and `rest`.
    let (packet, rest) = split.via_into_bytes();

    assert_eq!(packet.length, 4);
    assert_eq!(packet.body, [1, 2, 3, 4]);
    assert_eq!(rest, [5, 6, 7, 8, 9]);

    rest.fill(0);
}

assert_eq!(packet.length, 4);
assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]);
§ Code Generation

See SplitAt::split_at.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl<T> SplitAt for ManuallyDrop<T>
where T: SplitAt + ?Sized,

Source§

type Elem = <T as SplitAt>::Elem

Source§

impl<T> SplitAt for [T]

Source§

type Elem = T

Implementors§