use core::fmt;
use core::mem::size_of;
use super::*;
#[doc(inline)]
pub use crate::intel_vector as vector;
#[repr(transparent)]
pub struct Vector<T: Array, G = EmptyGroup, FS = ()>
where FS: Features<G> {
pub(crate) primitive: T::Primitive,
pub(crate) features: FeatureSet<G, FS>,
}
#[doc(hidden)]
#[macro_export]
macro_rules! intel_vector {
[$($elem:expr),* $(,)?] => {
const {
const fn transmute<E: $crate::intel::Element<LEN>, const LEN: usize>
(array: [E; LEN]) -> $crate::intel::Vector<[E; LEN]> {
let p = unsafe { $crate::__core::mem::transmute_copy(&array) };
$crate::intel::Vector::from_primitive(p)
}
transmute([$(const { $elem }),*])
}
};
[$elem:expr; $size:expr] => {
const {
const fn transmute<E, const LEN: usize>(elem: E)
-> $crate::intel::Vector<[E; LEN]>
where E: $crate::intel::Element<LEN> {
let array = [elem; LEN];
let p = unsafe { $crate::__core::mem::transmute_copy(&array) };
$crate::intel::Vector::from_primitive(p)
}
transmute::<_, $size>($elem)
}
};
}
impl<E: Element<LEN>, const LEN: usize> Vector<[E; LEN]> {
pub const fn from_primitive(primitive: E::Primitive) -> Self {
Self { primitive, features: FeatureSet::new(()) }
}
}
impl<E, G, FS, const LEN: usize> Vector<[E; LEN], G, FS>
where E: Element<LEN>, FS: Features<G> {
pub const fn features(self) -> FeatureSet<G, FS> {
self.features
}
pub const fn with_features<NG, NFS: Features<NG>>
(self, features: FeatureSet<NG, NFS>)
-> Vector<[E; LEN], NG, NFS> {
Vector { primitive: self.primitive, features }
}
pub const fn into_primitive(self) -> E::Primitive {
self.primitive
}
pub const fn as_array(&self) -> &[E; LEN] {
unsafe { &*(&self.primitive as *const _ as *const [E; LEN]) }
}
pub const fn slice_as_array(this: &[Self]) -> &[E] {
unsafe {
core::slice::from_raw_parts(
this.as_ptr() as *const E, this.len() * LEN)
}
}
#[inline]
pub const fn truncate<const NLEN: usize>(self) -> Vector<[E; NLEN], G, FS>
where E: Element<NLEN> {
const_assert!(NLEN <= LEN);
use core::mem::transmute_copy;
Vector::from_primitive(unsafe {
transmute_copy(&self.primitive)
}).with_features(self.features)
}
#[inline]
pub const fn cast<NE, const NLEN: usize>(self) -> Vector<[NE; NLEN], G, FS>
where NE: Element<NLEN> {
const_assert!(size_of::<[E; LEN]>() == size_of::<[NE; NLEN]>());
use core::mem::transmute_copy;
Vector::from_primitive(unsafe {
transmute_copy(&self.primitive)
}).with_features(self.features)
}
}
impl<E, G, FS, const LEN: usize> Clone for Vector<[E; LEN], G, FS>
where E: Element<LEN>, FS: Features<G> {
fn clone(&self) -> Self {
*self
}
}
impl<E, G, FS, const LEN: usize> Copy for Vector<[E; LEN], G, FS>
where E: Element<LEN>, FS: Features<G> {}
impl<E, G, FS, const LEN: usize> fmt::Debug for Vector<[E; LEN], G, FS>
where E: Element<LEN> + fmt::Debug, FS: Features<G> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_array().fmt(f)
}
}
#[cfg(feature = "proptest")]
mod props {
use super::*;
use proptest::arbitrary::Arbitrary;
use proptest::strategy::{*, Strategy};
use proptest::test_runner::TestRunner;
impl<E, const LEN: usize> Arbitrary for Vector<[E; LEN]>
where E: Element<LEN> + Arbitrary {
type Parameters = ();
type Strategy = VectorStrategy<<[E; LEN] as Arbitrary>::Strategy>;
fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
VectorStrategy(<[E; LEN]>::arbitrary())
}
}
#[derive(Clone, Debug)]
pub struct VectorStrategy<S>(S);
impl<S, E, const LEN: usize> Strategy for VectorStrategy<S>
where S: Strategy<Value = [E; LEN]>, E: Element<LEN> + fmt::Debug {
type Tree = VectorStrategy<S::Tree>;
type Value = Vector<[E; LEN]>;
fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
self.0.new_tree(runner).map(VectorStrategy)
}
}
impl<S, E, const LEN: usize> ValueTree for VectorStrategy<S>
where S: ValueTree<Value = [E; LEN]>, E: Element<LEN> + fmt::Debug {
type Value = Vector<[E; LEN]>;
fn current(&self) -> Self::Value {
let array = self.0.current();
Vector::from_primitive(unsafe {
core::mem::transmute_copy(&array)
})
}
fn simplify(&mut self) -> bool {
self.0.simplify()
}
fn complicate(&mut self) -> bool {
self.0.complicate()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn with_features() {
use feats::{Features, Feature, RuntimeSupport};
#[derive(Copy, Clone)]
struct Feat;
struct FeatGroup;
impl Features<FeatGroup> for Feat {
fn query(_: &RuntimeSupport) -> Option<Self> {
Some(Self)
}
}
impl Feature<FeatGroup> for Feat {}
let vector = vector![0u8; 16];
let _: Vector<_, FeatGroup, (Feat, ())>
= vector.with_features(FeatureSet::new((Feat, ())));
}
#[test]
fn truncate() {
let vector = vector![
0u8, 7, 1, 15, 4, 2, 8, 11, 5, 0, 6, 14, 12, 13, 3, 9
];
let shorter: Vector<[u8; 8]> = vector.truncate();
assert_eq!(shorter.as_array(), &[0u8, 7, 1, 15, 4, 2, 8, 11]);
}
#[test]
fn cast() {
let vector = vector![
0u8, 7, 1, 15, 4, 2, 8, 11, 5, 0, 6, 14, 12, 13, 3, 9
];
let casted: Vector<[u16; 8]> = vector.cast();
assert_eq!(casted.as_array(), &[
1792u16, 3841, 516, 2824, 5, 3590, 3340, 2307
]);
}
}