Trait SplitAt

unsafe trait SplitAt: KnownLayout<PointerMetadata = usize>

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").

Implementation

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

# use zerocopy_derive::{SplitAt, KnownLayout};
#[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.

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.

Associated Types

type Elem

The element type of the trailing slice.

Provided Methods

unsafe fn split_at_unchecked(self: &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.

fn split_at(self: &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};
# use zerocopy_derive::*;

#[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]);
unsafe fn split_at_mut_unchecked(self: &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.

fn split_at_mut(self: &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, or if the given l_len would result in the trailing padding of the left portion overlapping the right portion.

Examples

use zerocopy::{SplitAt, FromBytes};
# use zerocopy_derive::*;

#[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]);

Implementors