valence_nbt/conv.rs
1//! Zero-cost conversion functions for `valence_nbt`.
2//!
3//! While working with [`Value`], it is often necessary to convert between
4//! collections of signed and unsigned integer types due to API
5//! differences. For instance, you may be given a `&[i8]` from
6//! [`Value::ByteArray`], but functions like [`Write::write_all`] expect to
7//! receive a `&[u8]`.
8//!
9//! This module provides functions to perform conversions between these types
10//! with zero-cost and no `unsafe` code on your part.
11//!
12//! [`Value`]: crate::Value
13//! [`Value::ByteArray`]: crate::Value::ByteArray
14//! [`Write::write_all`]: std::io::Write::write_all
15
16use std::mem::ManuallyDrop;
17
18/// Converts a `Vec<u8>` into a `Vec<i8>` without cloning.
19#[inline]
20pub fn u8_vec_into_i8_vec(vec: Vec<u8>) -> Vec<i8> {
21 // SAFETY: Layouts of u8 and i8 are the same and we're being careful not to drop
22 // the original vec after calling Vec::from_raw_parts.
23 unsafe {
24 let mut vec = ManuallyDrop::new(vec);
25 Vec::from_raw_parts(vec.as_mut_ptr() as *mut i8, vec.len(), vec.capacity())
26 }
27}
28
29/// Converts a `Vec<i8>` into a `Vec<u8>` without cloning.
30#[inline]
31pub fn i8_vec_into_u8_vec(vec: Vec<i8>) -> Vec<u8> {
32 // SAFETY: Layouts of u8 and i8 are the same and we're being careful not to drop
33 // the original vec after calling Vec::from_raw_parts.
34 unsafe {
35 let mut vec = ManuallyDrop::new(vec);
36 Vec::from_raw_parts(vec.as_mut_ptr() as *mut u8, vec.len(), vec.capacity())
37 }
38}
39
40/// Converts a `&[u8]` into a `&[i8]`.
41#[inline]
42pub fn u8_slice_as_i8_slice(slice: &[u8]) -> &[i8] {
43 // SAFETY: i8 has the same layout as u8.
44 unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const i8, slice.len()) }
45}
46
47/// Converts a `&[i8]` into a `&[u8]`.
48#[inline]
49pub fn i8_slice_as_u8_slice(slice: &[i8]) -> &[u8] {
50 // SAFETY: i8 has the same layout as u8.
51 unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) }
52}