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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//! Zero-cost conversion functions for `valence_nbt`.
//!
//! While working with [`Value`], it is often necessary to convert between
//! collections of signed and unsigned integer types due to API
//! differences. For instance, you may be given a `&[i8]` from
//! [`Value::ByteArray`], but functions like [`Write::write_all`] expect to
//! receive a `&[u8]`.
//!
//! This module provides functions to perform conversions between these types
//! with zero-cost and no `unsafe` code on your part.
//!
//! [`Value`]: crate::Value
//! [`Value::ByteArray`]: crate::Value::ByteArray
//! [`Write::write_all`]: std::io::Write::write_all

use std::mem::ManuallyDrop;

/// Converts a `Vec<u8>` into a `Vec<i8>` without cloning.
#[inline]
pub fn u8_vec_into_i8_vec(vec: Vec<u8>) -> Vec<i8> {
    // SAFETY: Layouts of u8 and i8 are the same and we're being careful not to drop
    // the original vec after calling Vec::from_raw_parts.
    unsafe {
        let mut vec = ManuallyDrop::new(vec);
        Vec::from_raw_parts(vec.as_mut_ptr() as *mut i8, vec.len(), vec.capacity())
    }
}

/// Converts a `Vec<i8>` into a `Vec<u8>` without cloning.
#[inline]
pub fn i8_vec_into_u8_vec(vec: Vec<i8>) -> Vec<u8> {
    // SAFETY: Layouts of u8 and i8 are the same and we're being careful not to drop
    // the original vec after calling Vec::from_raw_parts.
    unsafe {
        let mut vec = ManuallyDrop::new(vec);
        Vec::from_raw_parts(vec.as_mut_ptr() as *mut u8, vec.len(), vec.capacity())
    }
}

/// Converts a `&[u8]` into a `&[i8]`.
#[inline]
pub fn u8_slice_as_i8_slice(slice: &[u8]) -> &[i8] {
    // SAFETY: i8 has the same layout as u8.
    unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const i8, slice.len()) }
}

/// Converts a `&[i8]` into a `&[u8]`.
#[inline]
pub fn i8_slice_as_u8_slice(slice: &[i8]) -> &[u8] {
    // SAFETY: i8 has the same layout as u8.
    unsafe { std::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) }
}