pub struct Texel<P: ?Sized>(/* private fields */);Expand description
Marker struct to denote a texel type.
Can be constructed only for types that have expected alignment and no byte invariants. It
always implements Copy and Clone, regardless of the underlying type and is zero-sized.
This is the central encapsulation of unsafety in this crate. It utilizes bytemuck for a safe
interface but permits other types with an unsafe interface, and offers the cast operations
without a bound on the Pod trait. Note that Pod is a pure marker trait; its properties must
hold even if it is not explicitly mentioned. If all constructors (safely or unsafely) ensure
that its properties hold we can use Texel as a witness type for the bound and subsequently
write interfaces to take an instance instead of having a static type bound. This achieves two
effects:
- Firstly, it makes the interface independent of the chosen transmutation crate. Potentially we
will have a method to construct the
Texelvia acoretrait. - Secondly, it allows creating texel of third-party types for which the bound can not be implemented. Crucially, this includes SIMD representations that would be a burden to support directly. And conversely you can also deal with arbitrary existing texel without a bound in your own interfaces!
Implementations§
Source§impl<P: Pod> Texel<P>
impl<P: Pod> Texel<P>
Sourcepub const fn for_type() -> Option<Self>
pub const fn for_type() -> Option<Self>
Try to construct an instance of the marker.
If successful, you can freely use it to access the image buffers. This requires:
- The type must have an alignment of at most
MAX_ALIGN. - The type must not be a ZST.
- The type must not have any Drop-glue (no drop, any contain not part that is Drop).
Source§impl<P> Texel<P>
impl<P> Texel<P>
Sourcepub const unsafe fn new_unchecked() -> Self
pub const unsafe fn new_unchecked() -> Self
Create a witness certifying P as a texel without checks.
§Safety
The type P must not:
- have any validity invariants, i.e. is mustn’t contain any padding.
- have any safety invariants. This implies it can be copied.
- have an alignment larger than
MaxAligned. - be a zero-size type.
Furthermore, tentatively, the type must not have any drop glue. That is its members are all simple types without Drop implementations. This requirement exists mainly to avoid code accidentally leaking instances, and ensures that copies created from their byte representation—which is safe according to the other invairants— do not cause unexpected effects.
Note that the alignment requirement with regards to MaxAligned is architecture
dependent as the exact bound varies across the target_arch feature. Where possible, add
static assertions to each call site of this function.
Sourcepub const fn size_nz(self) -> NonZeroUsize
pub const fn size_nz(self) -> NonZeroUsize
Publicly visible function to use the guarantee of non-ZST.
Sourcepub const fn array<const N: usize>(self) -> Texel<[P; N]>
pub const fn array<const N: usize>(self) -> Texel<[P; N]>
Construct a texel as an array of no elements.
§Panics
This function panics when called with N equal to 0.
Sourcepub const fn unaligned(self) -> Texel<Unaligned<P>>
pub const fn unaligned(self) -> Texel<Unaligned<P>>
Construct a texel for unaligned data of the contained type.
Sourcepub const fn transparent_wrap<O>(
self,
_: IsTransparentWrapper<P, O>,
) -> Texel<O>
pub const fn transparent_wrap<O>( self, _: IsTransparentWrapper<P, O>, ) -> Texel<O>
Construct a texel by wrapping into a transparent wrapper.
TODO: a constructor for Texel<O> based on proof of transmutation from &mut P to &mut O,
based on the standard transmutation RFC. This is more flexible than bytemuck’s
TransparentWrapper trait.
Sourcepub const fn transparent_unwrap<O>(
self,
_: IsTransparentWrapper<O, P>,
) -> Texel<O>
pub const fn transparent_unwrap<O>( self, _: IsTransparentWrapper<O, P>, ) -> Texel<O>
Construct a texel by unwrapping a transparent wrapper.
Sourcepub const fn num_wrapping(self) -> Texel<Wrapping<P>>
pub const fn num_wrapping(self) -> Texel<Wrapping<P>>
Construct a texel that contains a number in the standard Wrapping type.
Source§impl<T, const N: usize> Texel<[T; N]>
impl<T, const N: usize> Texel<[T; N]>
Sourcepub const fn array_element(self) -> Texel<T>
pub const fn array_element(self) -> Texel<T>
Construct a texel, from an array of elements.
Source§impl<P> Texel<P>
Operations that can be performed based on the evidence of Texel.
impl<P> Texel<P>
Operations that can be performed based on the evidence of Texel.
Sourcepub fn copy_val(self, val: &P) -> P
pub fn copy_val(self, val: &P) -> P
Copy a texel.
Note that this does not require Copy because that requirement was part of the
requirements of constructing this Texel witness.
pub fn copy_cell(self, val: &Cell<P>) -> P
Sourcepub fn cell_as_slice(self, val: &[Cell<P>]) -> &Cell<[P]>
pub fn cell_as_slice(self, val: &[Cell<P>]) -> &Cell<[P]>
Undo a Cell::as_slice_of_cells call.
Sourcepub fn store_cell_slice(self, val: &[Cell<P>], from: &[P])
pub fn store_cell_slice(self, val: &[Cell<P>], from: &[P])
Efficiently store a slice of shared read values to cells.
We choose an outer slice for the parameter only since the standard library offers the
transposition out of the type parameter, but not its inverse yet. Call
Cell::as_slice_of_cells as needed.
Sourcepub fn load_cell_slice(self, val: &[Cell<P>], into: &mut [P])
pub fn load_cell_slice(self, val: &[Cell<P>], into: &mut [P])
Efficiently copy a slice of values from cells to an owned buffer.
We choose an outer slice for the parameter only since the standard library offers the
transposition out of the type parameter, but not its inverse yet. Call
Cell::as_slice_of_cells as needed.
Sourcepub fn load_atomic(self, val: AtomicRef<'_, P>) -> P
pub fn load_atomic(self, val: AtomicRef<'_, P>) -> P
Load a value from an atomic slice.
The results is only correct if no concurrent modification occurs. The library promises basic soundness but no particular defined behaviour under parallel modifications to the memory bytes which describe the value to be loaded.
Each atomic unit is read at most once.
Sourcepub fn load_atomic_slice(self, val: AtomicSliceRef<'_, P>, into: &mut [P])
pub fn load_atomic_slice(self, val: AtomicSliceRef<'_, P>, into: &mut [P])
Load values from an atomic slice.
The results is only correct if no concurrent modification occurs. The library promises basic soundness but no particular defined behaviour under parallel modifications to the memory bytes which describe the value to be loaded.
Each atomic unit is read at most once.
§Panics
This method panics if the slice and the target buffer do not have the same logical length.
Sourcepub fn load_atomic_to_cells(self, val: AtomicSliceRef<'_, P>, into: &[Cell<P>])
pub fn load_atomic_to_cells(self, val: AtomicSliceRef<'_, P>, into: &[Cell<P>])
Load values from an atomic slice to a slice of cells.
The results is only correct if no concurrent modification occurs. The library promises basic soundness but no particular defined behaviour under parallel modifications to the memory bytes which describe the value to be loaded.
Each atomic unit is read at most once.
§Panics
This method panics if the slice and the target buffer do not have the same length.
Sourcepub fn store_atomic(self, val: AtomicRef<'_, P>, value: P)
pub fn store_atomic(self, val: AtomicRef<'_, P>, value: P)
Store a value to an atomic slice.
The results is only correct if no concurrent modification occurs. The library promises basic soundness but no particular defined behaviour under parallel modifications to the memory bytes which describe the value to be store.
Provides the same wait-freeness as the underlying platform for fetch_* instructions, that
is this does not use compare_exchange_weak. This implies that concurrent modifications to
bytes not covered by this particular representation will not inherently block progress.
Sourcepub fn store_atomic_slice(self, val: AtomicSliceRef<'_, P>, source: &[P])
pub fn store_atomic_slice(self, val: AtomicSliceRef<'_, P>, source: &[P])
Store values to an atomic slice.
The results is only correct if no concurrent modification occurs. The library promises basic soundness but no particular defined behaviour under parallel modifications to the memory bytes which describe the value to be store.
Provides the same wait-freeness as the underlying platform for fetch_* instructions, that
is this does not use compare_exchange_weak. This implies that concurrent modifications to
bytes not covered by this particular representation will not inherently block progress.
§Panics
This method panics if the slice and the source buffer do not have the same logical length.
Sourcepub fn store_atomic_from_cells(
self,
val: AtomicSliceRef<'_, P>,
source: &[Cell<P>],
)
pub fn store_atomic_from_cells( self, val: AtomicSliceRef<'_, P>, source: &[Cell<P>], )
Store values from cells to an atomic slice.
The results is only correct if no concurrent modification occurs. The library promises basic soundness but no particular defined behaviour under parallel modifications to the memory bytes which describe the value to be store.
Provides the same wait-freeness as the underlying platform for fetch_* instructions, that
is this does not use compare_exchange_weak. This implies that concurrent modifications to
bytes not covered by this particular representation will not inherently block progress.
§Panics
This method panics if the slice and the source buffer do not have the same logical length.
Sourcepub fn to_slice<'buf>(self, buffer: &'buf [MaxAligned]) -> &'buf [P]
pub fn to_slice<'buf>(self, buffer: &'buf [MaxAligned]) -> &'buf [P]
Reinterpret a slice of aligned bytes as a slice of the texel.
Note that the size (in bytes) of the slice will be shortened if the size of P is not a
divisor of the input slice’s size.
Sourcepub fn to_mut_slice<'buf>(self, buffer: &'buf mut [MaxAligned]) -> &'buf mut [P]
pub fn to_mut_slice<'buf>(self, buffer: &'buf mut [MaxAligned]) -> &'buf mut [P]
Reinterpret a slice of aligned bytes as a mutable slice of the texel.
Note that the size (in bytes) of the slice will be shortened if the size of P is not a
divisor of the input slice’s size.
Sourcepub fn try_to_slice<'buf>(self, bytes: &'buf [u8]) -> Option<&'buf [P]>
pub fn try_to_slice<'buf>(self, bytes: &'buf [u8]) -> Option<&'buf [P]>
Try to reinterpret a slice of bytes as a slice of the texel.
This returns Some if the buffer is suitably aligned, and None otherwise.
Sourcepub fn try_to_slice_mut<'buf>(
self,
bytes: &'buf mut [u8],
) -> Option<&'buf mut [P]>
pub fn try_to_slice_mut<'buf>( self, bytes: &'buf mut [u8], ) -> Option<&'buf mut [P]>
Try to reinterpret a slice of bytes as a slice of the texel.
This returns Some if the buffer is suitably aligned, and None otherwise.
Sourcepub fn to_unaligned_slice<'buf>(self, bytes: &'buf [u8]) -> &'buf [Unaligned<P>]
pub fn to_unaligned_slice<'buf>(self, bytes: &'buf [u8]) -> &'buf [Unaligned<P>]
Interpret a byte slice as unaligned values of another type.
This is essentially a call to Texel::to_slice however the specific output type
selection ensures that it always succeeds.
§Examples
use image_texel::texels::{U8, U64};
// This buffer is not guaranteed to be aligned!
let raw_buffer = [0u16, 1, 2, 3].map(u16::to_be_bytes);
let raw_bytes = U8.array().to_bytes(&raw_buffer);
let unaligned = U64.to_unaligned_slice(raw_bytes);
// Forces a copy. `texel.unaligned().copy` would work, too.
assert_eq!(u64::from_be(unaligned[0].0), 0x0000_0001_0002_0003);Sourcepub fn to_unaligned_slice_mut<'buf>(
self,
bytes: &'buf mut [u8],
) -> &'buf mut [Unaligned<P>]
pub fn to_unaligned_slice_mut<'buf>( self, bytes: &'buf mut [u8], ) -> &'buf mut [Unaligned<P>]
Interpret a mutable byte slice as unaligned values of another type.
§Examples
use image_texel::texels::{U16, U64};
// This buffer is not guaranteed to be aligned!
let mut raw_buffer = [0u16; 4];
let raw_bytes = U16.to_mut_bytes(&mut raw_buffer);
let unaligned = U64.to_unaligned_slice_mut(raw_bytes);
unaligned[0].0 = u64::from_be(0x0000_0001_0002_0003);
assert_eq!(raw_buffer.map(u16::from_be), [0, 1, 2, 3]);Sourcepub fn to_cell<'buf>(self, buffer: &'buf [MaxCell]) -> &'buf Cell<[P]>
pub fn to_cell<'buf>(self, buffer: &'buf [MaxCell]) -> &'buf Cell<[P]>
Reinterpret a shared slice as a some particular type.
Note that the size (in bytes) of the slice will be shortened if the size of P is not a
divisor of the input slice’s size.
Sourcepub fn try_to_cell<'buf>(
self,
bytes: &'buf [Cell<u8>],
) -> Option<&'buf Cell<[P]>>
pub fn try_to_cell<'buf>( self, bytes: &'buf [Cell<u8>], ) -> Option<&'buf Cell<[P]>>
Reinterpret a slice of texel as memory.
Note that you can convert a reference to a single value by core::slice::from_ref.
Sourcepub fn to_unaligned_cell<'buf>(
self,
bytes: &'buf [Cell<u8>],
) -> &'buf Cell<[Unaligned<P>]>
pub fn to_unaligned_cell<'buf>( self, bytes: &'buf [Cell<u8>], ) -> &'buf Cell<[Unaligned<P>]>
Interpret a slice of cells as unaligned cells of another type.
§Examples
use core::cell::Cell;
use image_texel::texels::{U16, U64};
// This buffer is not guaranteed to be aligned to u64!
let mut raw_buffer = [0u16; 4].map(Cell::new);
let raw_bytes = U16.cell_bytes(&raw_buffer).as_slice_of_cells();
// Write a u64 value anyways.
let unaligned = U64.to_unaligned_cell(raw_bytes).as_slice_of_cells();
unaligned[0].set(u64::from_be(0x0000_0001_0002_0003).into());
let raw_buffer = raw_buffer.map(Cell::into_inner);
assert_eq!(raw_buffer.map(u16::from_be), [0, 1, 2, 3]);Sourcepub fn try_to_atomic<'buf>(
self,
bytes: AtomicSliceRef<'buf, u8>,
) -> Option<AtomicSliceRef<'buf, P>>
pub fn try_to_atomic<'buf>( self, bytes: AtomicSliceRef<'buf, u8>, ) -> Option<AtomicSliceRef<'buf, P>>
Reinterpret a slice of atomically access memory with a type annotation.
Sourcepub fn to_unaligned_atomic<'buf>(
self,
bytes: AtomicSliceRef<'buf, u8>,
) -> AtomicSliceRef<'buf, Unaligned<P>>
pub fn to_unaligned_atomic<'buf>( self, bytes: AtomicSliceRef<'buf, u8>, ) -> AtomicSliceRef<'buf, Unaligned<P>>
Interpret a slice of cells as unaligned atomic values of another type.
§Examples
use image_texel::texels::atomic_buf;
use image_texel::texels::{MaxAtomic, U16, U64};
let underlying = [MaxAtomic::zero(); 1];
let raw_buffer = atomic_buf::new(&underlying[..]);
// Get a partial slice of it, that is is not aligned to u64.
let u16_slice = raw_buffer.index(U16.to_range(1..5).unwrap());
let raw_bytes = U16.atomic_bytes(u16_slice);
// Re-Interpret that as an unaligned slice of u64 values.
let unaligned = U64.to_unaligned_atomic(raw_bytes);
std::thread::scope(|scope| {
scope.spawn(|| {
// Write a u64 value.
U64.unaligned().store_atomic(
unaligned.index_one(0),
u64::from_be(0x0000_0001_0002_0003).into()
)
});
});
// Load from the buffer we've written to atomically.
let mut values = [0; 4];
U16.load_atomic_slice(u16_slice, &mut values[..]);
assert_eq!(values.map(u16::from_be), [0u16, 1, 2, 3]);Sourcepub fn to_bytes<'buf>(self, texel: &'buf [P]) -> &'buf [u8]
pub fn to_bytes<'buf>(self, texel: &'buf [P]) -> &'buf [u8]
Reinterpret a slice of texel as memory.
Note that you can convert a reference to a single value by core::slice::from_ref.
Sourcepub fn to_mut_bytes<'buf>(self, texel: &'buf mut [P]) -> &'buf mut [u8]
pub fn to_mut_bytes<'buf>(self, texel: &'buf mut [P]) -> &'buf mut [u8]
Reinterpret a mutable slice of texel as memory.
Note that you can convert a reference to a single value by core::slice::from_mut.
Sourcepub fn cell_bytes<'buf>(self, texel: &'buf [Cell<P>]) -> &'buf Cell<[u8]>
pub fn cell_bytes<'buf>(self, texel: &'buf [Cell<P>]) -> &'buf Cell<[u8]>
Reinterpret a slice of texel as memory.
Note that you can convert a reference to a single value by core::slice::from_ref.
Sourcepub fn atomic_bytes<'buf>(
self,
texel: AtomicSliceRef<'buf, P>,
) -> AtomicSliceRef<'buf, u8>
pub fn atomic_bytes<'buf>( self, texel: AtomicSliceRef<'buf, P>, ) -> AtomicSliceRef<'buf, u8>
Reinterpret a slice of atomically modified texels as atomic bytes.
Sourcepub fn to_range(self, range: Range<usize>) -> Option<TexelRange<P>>
pub fn to_range(self, range: Range<usize>) -> Option<TexelRange<P>>
Construct a range indexing to a slice of this texel.
See TexelRange::new as this is just a proxy.
use image_texel::{texels::{U16, buf}, TexelBuffer};
let buffer = TexelBuffer::with_elements(&[1u32, 2, 3, 4]);
let range = U16.to_range(4..8).unwrap();
let u16_view = &buffer.as_buf()[range];
assert_eq!(u16_view.len(), 4);
// This view extends over the `3u32` and `4u32` elements.
// Results depend on native endianess of the `u32` type.
assert!(u16_view[0] == 3 || u16_view[1] == 3);
assert!(u16_view[2] == 4 || u16_view[3] == 4);Sourcepub fn to_byte_range(self, range: Range<usize>) -> Option<TexelRange<P>>
pub fn to_byte_range(self, range: Range<usize>) -> Option<TexelRange<P>>
Construct a range indexing to a slice of this texel by bytes.
See TexelRange::from_byte_range as this is just a proxy.
Trait Implementations§
impl<P> Copy for Texel<P>
This is a pure marker type.
impl<P> Eq for Texel<P>
Source§impl<T> From<Texel<T>> for TexelLayout
Convert a pixel to an element, discarding the exact type information.
impl<T> From<Texel<T>> for TexelLayout
Convert a pixel to an element, discarding the exact type information.
Source§impl<P> Ord for Texel<P>
impl<P> Ord for Texel<P>
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl<P> PartialOrd for Texel<P>
impl<P> PartialOrd for Texel<P>
Source§impl<P> TryMend<MatrixBytes> for Texel<P>
Try to use the matrix with a specific pixel type.
impl<P> TryMend<MatrixBytes> for Texel<P>
Try to use the matrix with a specific pixel type.