pub unsafe trait UnsizedCopy {
type Alignment: Sized;
// Required method
fn ptr_with_addr(&self, addr: *const ()) -> *const Self;
// Provided methods
fn unsized_copy_into<T: UnsizedCopyFrom<Source = Self>>(&self) -> T { ... }
fn copy(&self) -> Self
where Self: Sized { ... }
}
Expand description
An extension of Copy
to dynamically sized types.
This is a generalization of Copy
. It is intended to simplify working
with DSTs that support zero-copy parsing techniques (as these are built
from byte sequences, they are inherently trivial to copy).
§Usage
To copy a type, call UnsizedCopy::unsized_copy_into()
on the DST being
copied, or call UnsizedCopyFrom::unsized_copy_from()
on the container
type to copy into. The two function identically.
§Safety
A type T
can implement UnsizedCopy
if all of the following hold:
-
It is an aggregate type (
struct
,enum
, orunion
) and every field implementsUnsizedCopy
. -
T::Alignment
has exactly the same alignment asT
. -
T::ptr_with_addr()
satisfies the documented invariants.
Required Associated Types§
Sourcetype Alignment: Sized
type Alignment: Sized
A type with the same alignment as Self
.
At the moment, Rust does not provide a way to determine the alignment
of a dynamically sized type at compile-time. This restriction exists
because trait objects (which count as DSTs, but are not supported by
UnsizedCopy
) have an alignment determined by their implementation
(which can vary at runtime).
This associated type papers over this limitation, by simply requiring
every implementation of UnsizedCopy
to specify a type with the
same alignment here. This is used by internal plumbing code to know
the alignment of Self
at compile-time.
§Invariants
The alignment of Self::Alignment
must be the same as that of Self
.
Required Methods§
Sourcefn ptr_with_addr(&self, addr: *const ()) -> *const Self
fn ptr_with_addr(&self, addr: *const ()) -> *const Self
Change the address of a pointer to Self
.
Self
may be a DST, which means that references (and pointers) to it
store metadata alongside the usual memory address. For example, the
metadata for a slice type is its length. In order to construct a new
instance of Self
(as is done by copying), a new pointer must be
created, and the appropriate metadata must be inserted.
At the moment, Rust does not provide a way to examine this metadata for an arbitrary type. This method papers over this limitation, and provides a way to copy the metadata from an existing pointer while changing the pointer address.
§Implementing
Most users will derive UnsizedCopy
and so don’t need to worry
about this. In any case, when Rust builds in support for extracting
metadata, this function will gain a default implementation, and will
eventually be deprecated.
For manual implementations for unsized types:
pub struct Foo {
a: i32,
b: [u8],
}
unsafe impl UnsizedCopy for Foo {
// We would like to write 'Alignment = Self' here, but we can't
// because 'Self' is not 'Sized'. However, 'Self' is a 'struct'
// using 'repr(Rust)'; the following tuple (which implicitly also
// uses 'repr(Rust)') has the same alignment as it.
type Alignment = (i32, u8);
fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
// Delegate to the same function on the last field.
//
// Rust knows that 'Self' has the same metadata as '[u8]',
// and so permits casting pointers between those types.
self.b.ptr_with_addr(addr) as *const Self
}
}
For manual implementations for sized types:
pub struct Foo {
a: i32,
b: Option<f64>,
}
unsafe impl UnsizedCopy for Foo {
// Because 'Foo' is a sized type, we can use it here directly.
type Alignment = Self;
fn ptr_with_addr(&self, addr: *const ()) -> *const Self {
// Since 'Self' is 'Sized', there is no metadata.
addr.cast::<Self>()
}
}
§Invariants
For the statement let result = Self::ptr_with_addr(ptr, addr);
, the
following always hold:
result as usize == addr as usize
.core::ptr::metadata(result) == core::ptr::metadata(ptr)
.
It is undefined behaviour for an implementation of UnsizedCopy
to
break these invariants.
Provided Methods§
Sourcefn unsized_copy_into<T: UnsizedCopyFrom<Source = Self>>(&self) -> T
fn unsized_copy_into<T: UnsizedCopyFrom<Source = Self>>(&self) -> T
Copy self
into a new container.
A new container of the specified type (which is usually inferred) is
allocated, and the contents of self
are copied into it. This is a
convenience method that calls unsized_copy_from()
.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.