mirror of
https://github.com/Lokathor/bytemuck.git
synced 2024-11-21 22:32:23 +00:00
commit
0628dab084
30
.travis.yml
30
.travis.yml
@ -4,7 +4,7 @@ git:
|
||||
quiet: true
|
||||
|
||||
rust:
|
||||
- 1.38.0
|
||||
- 1.34.0
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
@ -30,23 +30,23 @@ matrix:
|
||||
# If we wanted to flag on --release mode we'd add a line like this
|
||||
#- { os: linux, rust: 1.38.0, env: FLAGS=--release }
|
||||
|
||||
- { os: linux, rust: 1.38.0, env: TARGET=wasm32-unknown-unknown }
|
||||
- { os: linux, rust: 1.38.0, env: TARGET=wasm32-wasi }
|
||||
- { os: linux, rust: 1.34.0, env: TARGET=wasm32-unknown-unknown }
|
||||
#- { os: linux, rust: 1.34.0, env: TARGET=wasm32-wasi }
|
||||
|
||||
- { os: linux, rust: 1.38.0, env: TARGET=aarch64-linux-android }
|
||||
- { os: linux, rust: 1.38.0, env: TARGET=armv7-linux-androideabi }
|
||||
- { os: linux, rust: 1.38.0, env: TARGET=i686-linux-android }
|
||||
- { os: linux, rust: 1.38.0, env: TARGET=x86_64-linux-android }
|
||||
- { os: linux, rust: 1.34.0, env: TARGET=aarch64-linux-android }
|
||||
- { os: linux, rust: 1.34.0, env: TARGET=armv7-linux-androideabi }
|
||||
- { os: linux, rust: 1.34.0, env: TARGET=i686-linux-android }
|
||||
- { os: linux, rust: 1.34.0, env: TARGET=x86_64-linux-android }
|
||||
|
||||
- { os: linux, rust: 1.38.0, env: TARGET=arm-unknown-linux-gnueabihf }
|
||||
- { os: linux, rust: 1.38.0, env: TARGET=armv7-unknown-linux-gnueabihf }
|
||||
- { os: linux, rust: 1.38.0, env: TARGET=thumbv7neon-unknown-linux-gnueabihf }
|
||||
- { os: linux, rust: 1.34.0, env: TARGET=arm-unknown-linux-gnueabihf }
|
||||
- { os: linux, rust: 1.34.0, env: TARGET=armv7-unknown-linux-gnueabihf }
|
||||
- { os: linux, rust: 1.34.0, env: TARGET=thumbv7neon-unknown-linux-gnueabihf }
|
||||
|
||||
- { os: osx, rust: 1.38.0, env: TARGET=aarch64-apple-ios }
|
||||
- { os: osx, rust: 1.38.0, env: TARGET=armv7-apple-ios }
|
||||
- { os: osx, rust: 1.38.0, env: TARGET=armv7s-apple-ios }
|
||||
- { os: osx, rust: 1.38.0, env: TARGET=i386-apple-ios }
|
||||
- { os: osx, rust: 1.38.0, env: TARGET=x86_64-apple-ios }
|
||||
- { os: osx, rust: 1.34.0, env: TARGET=aarch64-apple-ios }
|
||||
- { os: osx, rust: 1.34.0, env: TARGET=armv7-apple-ios }
|
||||
- { os: osx, rust: 1.34.0, env: TARGET=armv7s-apple-ios }
|
||||
- { os: osx, rust: 1.34.0, env: TARGET=i386-apple-ios }
|
||||
- { os: osx, rust: 1.34.0, env: TARGET=x86_64-apple-ios }
|
||||
|
||||
script:
|
||||
- pushd scripts
|
||||
|
@ -8,7 +8,7 @@ readme = "README.md"
|
||||
keywords = ["transmute", "bytes", "casting"]
|
||||
categories = ["encoding", "no-std"]
|
||||
edition = "2018"
|
||||
license = "BlueOak-1.0.0"
|
||||
license = "Zlib"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
@ -1,55 +0,0 @@
|
||||
# Blue Oak Model License
|
||||
|
||||
Version 1.0.0
|
||||
|
||||
## Purpose
|
||||
|
||||
This license gives everyone as much permission to work with
|
||||
this software as possible, while protecting contributors
|
||||
from liability.
|
||||
|
||||
## Acceptance
|
||||
|
||||
In order to receive this license, you must agree to its
|
||||
rules. The rules of this license are both obligations
|
||||
under that agreement and conditions to your license.
|
||||
You must not do anything with this software that triggers
|
||||
a rule that you cannot or will not follow.
|
||||
|
||||
## Copyright
|
||||
|
||||
Each contributor licenses you to do everything with this
|
||||
software that would otherwise infringe that contributor's
|
||||
copyright in it.
|
||||
|
||||
## Notices
|
||||
|
||||
You must ensure that everyone who gets a copy of
|
||||
any part of this software from you, with or without
|
||||
changes, also gets the text of this license or a link to
|
||||
<https://blueoakcouncil.org/license/1.0.0>.
|
||||
|
||||
## Excuse
|
||||
|
||||
If anyone notifies you in writing that you have not
|
||||
complied with [Notices](#notices), you can keep your
|
||||
license by taking all practical steps to comply within 30
|
||||
days after the notice. If you do not do so, your license
|
||||
ends immediately.
|
||||
|
||||
## Patent
|
||||
|
||||
Each contributor licenses you to do everything with this
|
||||
software that would otherwise infringe any patent claims
|
||||
they can license or become able to license.
|
||||
|
||||
## Reliability
|
||||
|
||||
No contributor can revoke this license.
|
||||
|
||||
## No Liability
|
||||
|
||||
***As far as the law allows, this software comes as is,
|
||||
without any warranty or condition, and no contributor
|
||||
will be liable to anyone for any damages related to this
|
||||
software or this license, under any kind of legal claim.***
|
11
LICENSE-ZLIB.md
Normal file
11
LICENSE-ZLIB.md
Normal file
@ -0,0 +1,11 @@
|
||||
Copyright (c) 2019 Daniel "Lokathor" Gee.
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
12
README.md
12
README.md
@ -1,5 +1,5 @@
|
||||
[![License:BlueOak-1.0.0](https://img.shields.io/badge/License-BlueOak_1.0.0-brightgreen.svg)](https://blueoakcouncil.org/license/1.0.0)
|
||||
![Minimum Rust Version](https://img.shields.io/badge/Min%20Rust-1.38-green.svg)
|
||||
[![License:Zlib](https://img.shields.io/badge/License-Zlib-brightgreen.svg)](https://opensource.org/licenses/Zlib)
|
||||
![Minimum Rust Version](https://img.shields.io/badge/Min%20Rust-1.34-green.svg)
|
||||
[![travis.ci](https://travis-ci.org/Lokathor/bytemuck.svg?branch=master)](https://travis-ci.org/Lokathor/bytemuck)
|
||||
[![AppVeyor](https://ci.appveyor.com/api/projects/status/hgr4if0snmkmqj88/branch/master?svg=true)](https://ci.appveyor.com/project/Lokathor/bytemuck/branch/master)
|
||||
[![crates.io](https://img.shields.io/crates/v/bytemuck.svg)](https://crates.io/crates/bytemuck)
|
||||
@ -7,8 +7,8 @@
|
||||
|
||||
# bytemuck
|
||||
|
||||
A crate for mucking around with piles of bytes
|
||||
A crate for mucking around with piles of bytes.
|
||||
|
||||
CI coverage:
|
||||
* Tested on: `x86`, `x86_64`, `wasm`
|
||||
* Built on: `armv7`, `aarch64`, `thumbv7neon`
|
||||
## Stability
|
||||
|
||||
The goal is to stay at 1.0 until at least the next edition of Rust.
|
||||
|
10
appveyor.yml
10
appveyor.yml
@ -14,13 +14,13 @@ matrix:
|
||||
environment:
|
||||
matrix:
|
||||
# Stable
|
||||
- channel: 1.38.0
|
||||
- channel: 1.34.0
|
||||
target: i686-pc-windows-msvc
|
||||
- channel: 1.38.0
|
||||
- channel: 1.34.0
|
||||
target: i686-pc-windows-gnu
|
||||
- channel: 1.38.0
|
||||
- channel: 1.34.0
|
||||
target: x86_64-pc-windows-msvc
|
||||
- channel: 1.38.0
|
||||
- channel: 1.34.0
|
||||
target: x86_64-pc-windows-gnu
|
||||
# Beta and Nightly are checked by TravisCI since builds there run in
|
||||
# parallel.
|
||||
@ -42,4 +42,4 @@ test_script:
|
||||
- cargo clippy
|
||||
- cargo test --no-default-features
|
||||
- cargo test
|
||||
- cargo test --all-features
|
||||
#- cargo test --all-features
|
||||
|
7
changelog.md
Normal file
7
changelog.md
Normal file
@ -0,0 +1,7 @@
|
||||
# `bytemuck` changelog
|
||||
|
||||
## 1.0.1
|
||||
|
||||
* Changed to the [zlib](https://opensource.org/licenses/Zlib) license.
|
||||
* Added much more proper documentation.
|
||||
* Reduced the minimum Rust version to 1.34
|
@ -3,5 +3,6 @@ merge_imports = true
|
||||
reorder_imports = true
|
||||
use_try_shorthand = true
|
||||
tab_spaces = 2
|
||||
max_width = 100
|
||||
max_width = 80
|
||||
color = "Never"
|
||||
use_small_heuristics = "Max"
|
||||
|
@ -11,21 +11,21 @@ if [[ "$TARGET" == "wasm32-"* && "$TARGET" != "wasm32-wasi" ]]; then
|
||||
cargo-web --version || cargo install cargo-web
|
||||
cargo web test --no-default-features $FLAGS --target=$TARGET
|
||||
cargo web test $FLAGS --target=$TARGET
|
||||
cargo web test --all-features $FLAGS --target=$TARGET
|
||||
#cargo web test --all-features $FLAGS --target=$TARGET
|
||||
|
||||
elif [[ "$TARGET" == *"-linux-android"* ]]; then
|
||||
export PATH=/usr/local/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
|
||||
pushd linux-android
|
||||
cargo build --no-default-features --target=$TARGET $FLAGS
|
||||
cargo build --target=$TARGET $FLAGS
|
||||
cargo build --all-features --target=$TARGET $FLAGS
|
||||
#cargo build --all-features --target=$TARGET $FLAGS
|
||||
# Don't test, can't run android emulators successfully on travis currently
|
||||
popd
|
||||
|
||||
elif [[ "$TARGET" == *"-apple-ios" || "$TARGET" == "wasm32-wasi" ]]; then
|
||||
cargo build --no-default-features --target=$TARGET $FLAGS
|
||||
cargo build --target=$TARGET $FLAGS
|
||||
cargo build --all-features --target=$TARGET $FLAGS
|
||||
#cargo build --all-features --target=$TARGET $FLAGS
|
||||
# Don't test
|
||||
# iOS simulator setup/teardown is complicated
|
||||
# cargo-web doesn't support wasm32-wasi yet, nor can wasm-pack test specify a target
|
||||
@ -36,7 +36,7 @@ elif [[ "$TARGET" == *"-unknown-linux-gnueabihf" ]]; then
|
||||
pushd generic-cross
|
||||
cargo build --no-default-features --target=$TARGET $FLAGS
|
||||
cargo build --target=$TARGET $FLAGS
|
||||
cargo build --all-features --target=$TARGET $FLAGS
|
||||
#cargo build --all-features --target=$TARGET $FLAGS
|
||||
# Don't test
|
||||
popd
|
||||
|
||||
@ -44,12 +44,12 @@ elif [[ "$TARGET" != "" ]]; then
|
||||
pushd generic-cross
|
||||
cargo test --no-default-features --target=$TARGET $FLAGS
|
||||
cargo test --target=$TARGET $FLAGS
|
||||
cargo test --all-features --target=$TARGET $FLAGS
|
||||
#cargo test --all-features --target=$TARGET $FLAGS
|
||||
popd
|
||||
|
||||
else
|
||||
# Push nothing, target host CPU architecture
|
||||
cargo test --no-default-features $FLAGS
|
||||
cargo test $FLAGS
|
||||
cargo test --all-features $FLAGS
|
||||
#cargo test --all-features $FLAGS
|
||||
fi
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Stuff to boost things in the `alloc` crate.
|
||||
//!
|
||||
//! You must use the crate with the `extern_crate_alloc` feature for the content
|
||||
//! in this module to be compiled in!
|
||||
//! * You must enable the `extern_crate_alloc` feature of `bytemuck` or you will
|
||||
//! not be able to use this module!
|
||||
|
||||
use super::*;
|
||||
use alloc::{
|
||||
@ -26,14 +26,16 @@ pub fn cast_box<A: Pod, B: Pod>(input: Box<A>) -> Box<B> {
|
||||
/// alignment.
|
||||
/// * The start and end size of the `Box` must have the exact same size.
|
||||
#[inline]
|
||||
pub fn try_cast_box<A: Pod, B: Pod>(input: Box<A>) -> Result<Box<B>, (PodCastError, Box<A>)> {
|
||||
pub fn try_cast_box<A: Pod, B: Pod>(
|
||||
input: Box<A>,
|
||||
) -> Result<Box<B>, (PodCastError, Box<A>)> {
|
||||
if align_of::<A>() != align_of::<B>() {
|
||||
Err((PodCastError::AlignmentMismatch, input))
|
||||
} else if size_of::<A>() != size_of::<B>() {
|
||||
Err((PodCastError::SizeMismatch, input))
|
||||
} else {
|
||||
// Note(Lokathor): This is much simpler than with the Vec casting!
|
||||
let ptr: *mut B = Box::into_raw(input).cast::<B>();
|
||||
let ptr: *mut B = Box::into_raw(input) as *mut B;
|
||||
Ok(unsafe { Box::from_raw(ptr) })
|
||||
}
|
||||
}
|
||||
@ -53,13 +55,14 @@ pub fn try_zeroed_box<T: Zeroable>() -> Result<Box<T>, ()> {
|
||||
if size_of::<T>() == 0 {
|
||||
return Ok(Box::new(T::zeroed()));
|
||||
}
|
||||
let layout = Layout::from_size_align(size_of::<T>(), align_of::<T>()).unwrap();
|
||||
let layout =
|
||||
Layout::from_size_align(size_of::<T>(), align_of::<T>()).unwrap();
|
||||
let ptr = unsafe { alloc_zeroed(layout) };
|
||||
if ptr.is_null() {
|
||||
// we don't know what the error is because `alloc_zeroed` is a dumb API
|
||||
Err(())
|
||||
} else {
|
||||
Ok(unsafe { Box::<T>::from_raw(ptr.cast::<T>()) })
|
||||
Ok(unsafe { Box::<T>::from_raw(ptr as *mut T) })
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +91,9 @@ pub fn cast_vec<A: Pod, B: Pod>(input: Vec<A>) -> Vec<B> {
|
||||
/// capacity and length get adjusted during transmutation, but for now it's
|
||||
/// absolute.
|
||||
#[inline]
|
||||
pub fn try_cast_vec<A: Pod, B: Pod>(input: Vec<A>) -> Result<Vec<B>, (PodCastError, Vec<A>)> {
|
||||
pub fn try_cast_vec<A: Pod, B: Pod>(
|
||||
input: Vec<A>,
|
||||
) -> Result<Vec<B>, (PodCastError, Vec<A>)> {
|
||||
if align_of::<A>() != align_of::<B>() {
|
||||
Err((PodCastError::AlignmentMismatch, input))
|
||||
} else if size_of::<A>() != size_of::<B>() {
|
||||
@ -108,7 +113,7 @@ pub fn try_cast_vec<A: Pod, B: Pod>(input: Vec<A>) -> Result<Vec<B>, (PodCastErr
|
||||
// "into raw parts" method, which we can switch this too eventually.
|
||||
let mut manual_drop_vec = ManuallyDrop::new(input);
|
||||
let vec_ptr: *mut A = manual_drop_vec.as_mut_ptr();
|
||||
let ptr: *mut B = vec_ptr.cast::<B>();
|
||||
let ptr: *mut B = vec_ptr as *mut B;
|
||||
Ok(unsafe { Vec::from_raw_parts(ptr, length, capacity) })
|
||||
}
|
||||
}
|
||||
|
81
src/lib.rs
81
src/lib.rs
@ -1,4 +1,41 @@
|
||||
#![no_std]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
//! This crate gives small utilities for casting between plain data types.
|
||||
//!
|
||||
//! ## Basics
|
||||
//!
|
||||
//! Data comes in five basic forms in Rust, so we have five basic casting
|
||||
//! functions:
|
||||
//!
|
||||
//! * `T` uses [`cast`]
|
||||
//! * `&T` uses [`cast_ref`]
|
||||
//! * `&mut T` uses [`cast_mut`]
|
||||
//! * `&[T]` uses [`cast_slice`]
|
||||
//! * `&mut [T]` uses [`cast_slice_mut`]
|
||||
//!
|
||||
//! Some casts will never fail (eg: `cast::<u32, f32>` always works), other
|
||||
//! casts might fail (eg: `cast_ref::<[u8; 4], u32>` will fail if the reference
|
||||
//! isn't already aligned to 4). Each casting function has a "try" version which
|
||||
//! will return a `Result`, and the "normal" version which will simply panic on
|
||||
//! invalid input.
|
||||
//!
|
||||
//! ## Using Your Own Types
|
||||
//!
|
||||
//! All the functions here are guarded by the [`Pod`] trait, which is a
|
||||
//! sub-trait of the [`Zeroable`] trait.
|
||||
//!
|
||||
//! If you're very sure that your type is eligible, you can implement those
|
||||
//! traits for your type and then they'll have full casting support. However,
|
||||
//! these traits are `unsafe`, and you should carefully read the requirements
|
||||
//! before adding the them to your own types.
|
||||
//!
|
||||
//! ## Features
|
||||
//!
|
||||
//! * This crate is core only by default, but if you're using Rust 1.36 or later
|
||||
//! you can enable the `extern_crate_alloc` cargo feature for some additional
|
||||
//! methods related to `Box` and `Vec`. Note that the `docs.rs` documentation
|
||||
//! is always built with `extern_crate_alloc` cargo feature enabled.
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub(crate) use core::arch::x86;
|
||||
@ -121,7 +158,9 @@ pub fn pod_align_to<T: Pod, U: Pod>(vals: &[T]) -> (&[T], &[U], &[T]) {
|
||||
|
||||
/// As `align_to_mut`, but safe because of the [`Pod`] bound.
|
||||
#[inline]
|
||||
pub fn pod_align_to_mut<T: Pod, U: Pod>(vals: &mut [T]) -> (&mut [T], &mut [U], &mut [T]) {
|
||||
pub fn pod_align_to_mut<T: Pod, U: Pod>(
|
||||
vals: &mut [T],
|
||||
) -> (&mut [T], &mut [U], &mut [T]) {
|
||||
unsafe { vals.align_to_mut::<U>() }
|
||||
}
|
||||
|
||||
@ -136,8 +175,8 @@ pub fn try_cast<A: Pod, B: Pod>(a: A) -> Result<B, PodCastError> {
|
||||
let mut b = B::zeroed();
|
||||
// Note(Lokathor): We copy in terms of `u8` because that allows us to bypass
|
||||
// any potential alignment difficulties.
|
||||
let ap = (&a as *const A).cast::<u8>();
|
||||
let bp = (&mut b as *mut B).cast::<u8>();
|
||||
let ap = &a as *const A as *const u8;
|
||||
let bp = &mut b as *mut B as *mut u8;
|
||||
unsafe { ap.copy_to_nonoverlapping(bp, size_of::<A>()) };
|
||||
Ok(b)
|
||||
} else {
|
||||
@ -155,10 +194,12 @@ pub fn try_cast<A: Pod, B: Pod>(a: A) -> Result<B, PodCastError> {
|
||||
pub fn try_cast_ref<A: Pod, B: Pod>(a: &A) -> Result<&B, PodCastError> {
|
||||
// Note(Lokathor): everything with `align_of` and `size_of` will optimize away
|
||||
// after monomorphization.
|
||||
if align_of::<B>() > align_of::<A>() && (a as *const A as usize) % align_of::<B>() != 0 {
|
||||
if align_of::<B>() > align_of::<A>()
|
||||
&& (a as *const A as usize) % align_of::<B>() != 0
|
||||
{
|
||||
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
|
||||
} else if size_of::<B>() == size_of::<A>() {
|
||||
Ok(unsafe { &*(a as *const A).cast::<B>() })
|
||||
Ok(unsafe { &*(a as *const A as *const B) })
|
||||
} else {
|
||||
Err(PodCastError::SizeMismatch)
|
||||
}
|
||||
@ -171,10 +212,12 @@ pub fn try_cast_ref<A: Pod, B: Pod>(a: &A) -> Result<&B, PodCastError> {
|
||||
pub fn try_cast_mut<A: Pod, B: Pod>(a: &mut A) -> Result<&mut B, PodCastError> {
|
||||
// Note(Lokathor): everything with `align_of` and `size_of` will optimize away
|
||||
// after monomorphization.
|
||||
if align_of::<B>() > align_of::<A>() && (a as *mut A as usize) % align_of::<B>() != 0 {
|
||||
if align_of::<B>() > align_of::<A>()
|
||||
&& (a as *mut A as usize) % align_of::<B>() != 0
|
||||
{
|
||||
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
|
||||
} else if size_of::<B>() == size_of::<A>() {
|
||||
Ok(unsafe { &mut *(a as *mut A).cast::<B>() })
|
||||
Ok(unsafe { &mut *(a as *mut A as *mut B) })
|
||||
} else {
|
||||
Err(PodCastError::SizeMismatch)
|
||||
}
|
||||
@ -200,15 +243,17 @@ pub fn try_cast_mut<A: Pod, B: Pod>(a: &mut A) -> Result<&mut B, PodCastError> {
|
||||
pub fn try_cast_slice<A: Pod, B: Pod>(a: &[A]) -> Result<&[B], PodCastError> {
|
||||
// Note(Lokathor): everything with `align_of` and `size_of` will optimize away
|
||||
// after monomorphization.
|
||||
if align_of::<B>() > align_of::<A>() && (a.as_ptr() as usize) % align_of::<B>() != 0 {
|
||||
if align_of::<B>() > align_of::<A>()
|
||||
&& (a.as_ptr() as usize) % align_of::<B>() != 0
|
||||
{
|
||||
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
|
||||
} else if size_of::<B>() == size_of::<A>() {
|
||||
Ok(unsafe { core::slice::from_raw_parts(a.as_ptr().cast::<B>(), a.len()) })
|
||||
Ok(unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, a.len()) })
|
||||
} else if size_of::<A>() == 0 || size_of::<B>() == 0 {
|
||||
Err(PodCastError::SizeMismatch)
|
||||
} else if core::mem::size_of_val(a) % size_of::<B>() == 0 {
|
||||
let new_len = core::mem::size_of_val(a) / size_of::<B>();
|
||||
Ok(unsafe { core::slice::from_raw_parts(a.as_ptr().cast::<B>(), new_len) })
|
||||
Ok(unsafe { core::slice::from_raw_parts(a.as_ptr() as *const B, new_len) })
|
||||
} else {
|
||||
Err(PodCastError::OutputSliceWouldHaveSlop)
|
||||
}
|
||||
@ -218,18 +263,26 @@ pub fn try_cast_slice<A: Pod, B: Pod>(a: &[A]) -> Result<&[B], PodCastError> {
|
||||
///
|
||||
/// As [`try_cast_slice`], but `&mut`.
|
||||
#[inline]
|
||||
pub fn try_cast_slice_mut<A: Pod, B: Pod>(a: &mut [A]) -> Result<&mut [B], PodCastError> {
|
||||
pub fn try_cast_slice_mut<A: Pod, B: Pod>(
|
||||
a: &mut [A],
|
||||
) -> Result<&mut [B], PodCastError> {
|
||||
// Note(Lokathor): everything with `align_of` and `size_of` will optimize away
|
||||
// after monomorphization.
|
||||
if align_of::<B>() > align_of::<A>() && (a.as_mut_ptr() as usize) % align_of::<B>() != 0 {
|
||||
if align_of::<B>() > align_of::<A>()
|
||||
&& (a.as_mut_ptr() as usize) % align_of::<B>() != 0
|
||||
{
|
||||
Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
|
||||
} else if size_of::<B>() == size_of::<A>() {
|
||||
Ok(unsafe { core::slice::from_raw_parts_mut(a.as_mut_ptr().cast::<B>(), a.len()) })
|
||||
Ok(unsafe {
|
||||
core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, a.len())
|
||||
})
|
||||
} else if size_of::<A>() == 0 || size_of::<B>() == 0 {
|
||||
Err(PodCastError::SizeMismatch)
|
||||
} else if core::mem::size_of_val(a) % size_of::<B>() == 0 {
|
||||
let new_len = core::mem::size_of_val(a) / size_of::<B>();
|
||||
Ok(unsafe { core::slice::from_raw_parts_mut(a.as_mut_ptr().cast::<B>(), new_len) })
|
||||
Ok(unsafe {
|
||||
core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, new_len)
|
||||
})
|
||||
} else {
|
||||
Err(PodCastError::OutputSliceWouldHaveSlop)
|
||||
}
|
||||
|
19
src/pod.rs
19
src/pod.rs
@ -16,10 +16,14 @@ use super::*;
|
||||
///
|
||||
/// * The type must be inhabited (eg: no
|
||||
/// [Infallible](core::convert::Infallible)).
|
||||
/// * The type must allow any bit pattern (eg: no `bool` or `char`).
|
||||
/// * The type must not contain any padding bytes (eg: no `(u8, u16)`).
|
||||
/// * A struct needs to have all fields be `Pod` and be `repr(C)`,
|
||||
/// `repr(transparent)`, or `repr(packed)`.
|
||||
/// * The type must allow any bit pattern (eg: no `bool` or `char`, which have
|
||||
/// illegal bit patterns).
|
||||
/// * The type must not contain any padding bytes, either in the middle or on
|
||||
/// the end (eg: no `#[repr(C)] struct Foo(u8, u16)`, which has padding in the
|
||||
/// middle, and also no `#[repr(C)] struct Foo(u16, u8)`, which has padding on
|
||||
/// the end).
|
||||
/// * The type needs to have all fields also be `Pod`.
|
||||
/// * The type needs to be `repr(C)`, `repr(transparent)`, or `repr(packed)`.
|
||||
pub unsafe trait Pod: Zeroable + Copy + 'static {}
|
||||
|
||||
unsafe impl Pod for () {}
|
||||
@ -58,9 +62,12 @@ unsafe impl<T: 'static> Pod for Option<NonNull<T>> {}
|
||||
unsafe impl<T: Pod> Pod for PhantomData<T> {}
|
||||
unsafe impl<T: Pod> Pod for ManuallyDrop<T> {}
|
||||
|
||||
// Note(Lokathor): MaybeUninit can NEVER be Pod.
|
||||
|
||||
impl_unsafe_marker_for_array!(
|
||||
Pod, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 48, 64, 96, 128, 256, 512, 1024, 2048, 4096
|
||||
Pod, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 48, 64, 96, 128, 256,
|
||||
512, 1024, 2048, 4096
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
|
@ -1,10 +1,14 @@
|
||||
use super::*;
|
||||
|
||||
/// Trait for types that can be safely created with [`zeroed`](core::mem::zeroed).
|
||||
/// Trait for types that can be safely created with
|
||||
/// [`zeroed`](core::mem::zeroed).
|
||||
///
|
||||
/// An all-zeroes value may or may not be the same value as the
|
||||
/// [Default](core::default::Default) value of the type.
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// * Your type must be _inhabited_ (eg: no
|
||||
/// * Your type must be inhabited (eg: no
|
||||
/// [Infallible](core::convert::Infallible)).
|
||||
/// * Your type must be allowed to be an "all zeroes" bit pattern (eg: no
|
||||
/// [`NonNull<T>`](core::ptr::NonNull)).
|
||||
@ -56,22 +60,40 @@ unsafe impl<T> Zeroable for *const T {}
|
||||
unsafe impl<T> Zeroable for Option<NonNull<T>> {}
|
||||
unsafe impl<T: Zeroable> Zeroable for PhantomData<T> {}
|
||||
unsafe impl<T: Zeroable> Zeroable for ManuallyDrop<T> {}
|
||||
unsafe impl<T> Zeroable for MaybeUninit<T> {}
|
||||
|
||||
// 2.0: add MaybeUninit
|
||||
//unsafe impl<T> Zeroable for MaybeUninit<T> {}
|
||||
|
||||
unsafe impl<A: Zeroable> Zeroable for (A,) {}
|
||||
unsafe impl<A: Zeroable, B: Zeroable> Zeroable for (A, B) {}
|
||||
unsafe impl<A: Zeroable, B: Zeroable, C: Zeroable> Zeroable for (A, B, C) {}
|
||||
unsafe impl<A: Zeroable, B: Zeroable, C: Zeroable, D: Zeroable> Zeroable for (A, B, C, D) {}
|
||||
unsafe impl<A: Zeroable, B: Zeroable, C: Zeroable, D: Zeroable, E: Zeroable> Zeroable
|
||||
for (A, B, C, D, E)
|
||||
unsafe impl<A: Zeroable, B: Zeroable, C: Zeroable, D: Zeroable> Zeroable
|
||||
for (A, B, C, D)
|
||||
{
|
||||
}
|
||||
unsafe impl<A: Zeroable, B: Zeroable, C: Zeroable, D: Zeroable, E: Zeroable, F: Zeroable> Zeroable
|
||||
for (A, B, C, D, E, F)
|
||||
unsafe impl<A: Zeroable, B: Zeroable, C: Zeroable, D: Zeroable, E: Zeroable>
|
||||
Zeroable for (A, B, C, D, E)
|
||||
{
|
||||
}
|
||||
unsafe impl<A: Zeroable, B: Zeroable, C: Zeroable, D: Zeroable, E: Zeroable, F: Zeroable, G: Zeroable>
|
||||
Zeroable for (A, B, C, D, E, F, G)
|
||||
unsafe impl<
|
||||
A: Zeroable,
|
||||
B: Zeroable,
|
||||
C: Zeroable,
|
||||
D: Zeroable,
|
||||
E: Zeroable,
|
||||
F: Zeroable,
|
||||
> Zeroable for (A, B, C, D, E, F)
|
||||
{
|
||||
}
|
||||
unsafe impl<
|
||||
A: Zeroable,
|
||||
B: Zeroable,
|
||||
C: Zeroable,
|
||||
D: Zeroable,
|
||||
E: Zeroable,
|
||||
F: Zeroable,
|
||||
G: Zeroable,
|
||||
> Zeroable for (A, B, C, D, E, F, G)
|
||||
{
|
||||
}
|
||||
unsafe impl<
|
||||
@ -88,8 +110,9 @@ unsafe impl<
|
||||
}
|
||||
|
||||
impl_unsafe_marker_for_array!(
|
||||
Zeroable, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 32, 48, 64, 96, 128, 256, 512, 1024, 2048, 4096
|
||||
Zeroable, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 48, 64, 96, 128, 256,
|
||||
512, 1024, 2048, 4096
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
|
Loading…
Reference in New Issue
Block a user