mod aligned;
mod array;
mod detect;
pub use aligned::{AlignedBuffer, AlignedVec, SIMD_ALIGNMENT};
pub use array::{
decode_f32_array, decode_f64_array, decode_i32_array, decode_i64_array, decode_u8_array,
encode_f32_array, encode_f64_array, encode_i32_array, encode_i64_array, encode_u8_array,
};
pub use detect::{detect_capability, is_simd_available, optimal_alignment, SimdCapability};
use crate::Result;
#[cfg(feature = "alloc")]
pub fn encode_simd_array<T: SimdEncodable>(data: &[T]) -> Result<alloc::vec::Vec<u8>> {
T::encode_simd(data)
}
#[cfg(feature = "alloc")]
pub fn decode_simd_array<T: SimdDecodable>(data: &[u8]) -> Result<alloc::vec::Vec<T>> {
T::decode_simd(data)
}
pub trait SimdEncodable: Sized + Copy {
#[cfg(feature = "alloc")]
fn encode_simd(data: &[Self]) -> Result<alloc::vec::Vec<u8>>;
fn encode_simd_into(data: &[Self], dst: &mut [u8]) -> Result<usize>;
}
pub trait SimdDecodable: Sized + Copy {
#[cfg(feature = "alloc")]
fn decode_simd(data: &[u8]) -> Result<alloc::vec::Vec<Self>>;
fn decode_simd_into(src: &[u8], dst: &mut [Self]) -> Result<usize>;
}
#[cfg(feature = "alloc")]
extern crate alloc;
impl SimdEncodable for f32 {
#[cfg(feature = "alloc")]
fn encode_simd(data: &[Self]) -> Result<alloc::vec::Vec<u8>> {
encode_f32_array(data)
}
fn encode_simd_into(data: &[Self], dst: &mut [u8]) -> Result<usize> {
array::encode_f32_array_into(data, dst)
}
}
impl SimdDecodable for f32 {
#[cfg(feature = "alloc")]
fn decode_simd(data: &[u8]) -> Result<alloc::vec::Vec<Self>> {
decode_f32_array(data)
}
fn decode_simd_into(src: &[u8], dst: &mut [Self]) -> Result<usize> {
array::decode_f32_array_into(src, dst)
}
}
impl SimdEncodable for f64 {
#[cfg(feature = "alloc")]
fn encode_simd(data: &[Self]) -> Result<alloc::vec::Vec<u8>> {
encode_f64_array(data)
}
fn encode_simd_into(data: &[Self], dst: &mut [u8]) -> Result<usize> {
array::encode_f64_array_into(data, dst)
}
}
impl SimdDecodable for f64 {
#[cfg(feature = "alloc")]
fn decode_simd(data: &[u8]) -> Result<alloc::vec::Vec<Self>> {
decode_f64_array(data)
}
fn decode_simd_into(src: &[u8], dst: &mut [Self]) -> Result<usize> {
array::decode_f64_array_into(src, dst)
}
}
impl SimdEncodable for i32 {
#[cfg(feature = "alloc")]
fn encode_simd(data: &[Self]) -> Result<alloc::vec::Vec<u8>> {
encode_i32_array(data)
}
fn encode_simd_into(data: &[Self], dst: &mut [u8]) -> Result<usize> {
array::encode_i32_array_into(data, dst)
}
}
impl SimdDecodable for i32 {
#[cfg(feature = "alloc")]
fn decode_simd(data: &[u8]) -> Result<alloc::vec::Vec<Self>> {
decode_i32_array(data)
}
fn decode_simd_into(src: &[u8], dst: &mut [Self]) -> Result<usize> {
array::decode_i32_array_into(src, dst)
}
}
impl SimdEncodable for i64 {
#[cfg(feature = "alloc")]
fn encode_simd(data: &[Self]) -> Result<alloc::vec::Vec<u8>> {
encode_i64_array(data)
}
fn encode_simd_into(data: &[Self], dst: &mut [u8]) -> Result<usize> {
array::encode_i64_array_into(data, dst)
}
}
impl SimdDecodable for i64 {
#[cfg(feature = "alloc")]
fn decode_simd(data: &[u8]) -> Result<alloc::vec::Vec<Self>> {
decode_i64_array(data)
}
fn decode_simd_into(src: &[u8], dst: &mut [Self]) -> Result<usize> {
array::decode_i64_array_into(src, dst)
}
}
impl SimdEncodable for u8 {
#[cfg(feature = "alloc")]
fn encode_simd(data: &[Self]) -> Result<alloc::vec::Vec<u8>> {
encode_u8_array(data)
}
fn encode_simd_into(data: &[Self], dst: &mut [u8]) -> Result<usize> {
array::encode_u8_array_into(data, dst)
}
}
impl SimdDecodable for u8 {
#[cfg(feature = "alloc")]
fn decode_simd(data: &[u8]) -> Result<alloc::vec::Vec<Self>> {
decode_u8_array(data)
}
fn decode_simd_into(src: &[u8], dst: &mut [Self]) -> Result<usize> {
array::decode_u8_array_into(src, dst)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simd_detection() {
let cap = detect_capability();
assert!(matches!(
cap,
SimdCapability::Avx512
| SimdCapability::Avx2
| SimdCapability::Sse42
| SimdCapability::Neon
| SimdCapability::Scalar
));
}
#[test]
fn test_is_simd_available() {
let _ = is_simd_available();
}
#[cfg(feature = "alloc")]
#[test]
fn test_f32_roundtrip() {
let data: alloc::vec::Vec<f32> = alloc::vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
let encoded = encode_simd_array(&data).expect("encode failed");
let decoded: alloc::vec::Vec<f32> = decode_simd_array(&encoded).expect("decode failed");
assert_eq!(data, decoded);
}
#[cfg(feature = "alloc")]
#[test]
fn test_i32_roundtrip() {
let data: alloc::vec::Vec<i32> = alloc::vec![-100, -1, 0, 1, 100, 1000, -1000, 42];
let encoded = encode_simd_array(&data).expect("encode failed");
let decoded: alloc::vec::Vec<i32> = decode_simd_array(&encoded).expect("decode failed");
assert_eq!(data, decoded);
}
#[cfg(feature = "alloc")]
#[test]
fn test_large_array() {
let data: alloc::vec::Vec<f64> = (0..1024).map(|i| i as f64 * 0.5).collect();
let encoded = encode_simd_array(&data).expect("encode failed");
let decoded: alloc::vec::Vec<f64> = decode_simd_array(&encoded).expect("decode failed");
assert_eq!(data, decoded);
}
}