Skip to main content

fearless_simd/
traits.rs

1// Copyright 2025 the Fearless_SIMD Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4#![expect(
5    missing_docs,
6    reason = "TODO: https://github.com/linebender/fearless_simd/issues/40"
7)]
8use crate::{Level, Simd, SimdBase};
9
10/// Element-wise selection between two SIMD vectors using `self`.
11pub trait Select<T> {
12    /// For each element of this mask, select the first operand if the element is all ones, and select the second
13    /// operand if the element is all zeroes.
14    ///
15    /// If a mask element is *not* all ones or all zeroes, the result is unspecified. It may vary depending on
16    /// architecture, feature level, the mask elements' width, the mask vector's width, or library version.
17    fn select(self, if_true: T, if_false: T) -> T;
18}
19
20// Same as pulp
21pub trait WithSimd {
22    type Output;
23
24    fn with_simd<S: Simd>(self, simd: S) -> Self::Output;
25}
26
27impl<R, F: FnOnce(Level) -> R> WithSimd for F {
28    type Output = R;
29
30    #[inline(always)]
31    fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
32        self(simd.level())
33    }
34}
35
36/// Conversion of SIMD types to and from raw bytes.
37pub trait Bytes: Sized {
38    type Bytes;
39
40    /// Convert this type to an array of bytes.
41    fn to_bytes(self) -> Self::Bytes;
42
43    /// Create an instance of this type from an array of bytes.
44    fn from_bytes(value: Self::Bytes) -> Self;
45
46    /// Bitcast directly from this type to another one of the same size.
47    fn bitcast<U: Bytes<Bytes = Self::Bytes>>(self) -> U {
48        U::from_bytes(self.to_bytes())
49    }
50}
51
52pub(crate) mod seal {
53    #[expect(
54        unnameable_types,
55        reason = "This is a sealed trait, so being unnameable is the entire point"
56    )]
57    pub trait Seal {}
58}
59
60/// Value conversion, adding a SIMD blessing.
61///
62/// Analogous to [`From`], but takes a SIMD token, which is used to bless
63/// the new value. Most such conversions are safe transmutes, but this
64/// trait also supports splats, and implementations can use the SIMD token
65/// to use an efficient splat intrinsic.
66///
67/// The [`SimdInto`] trait is also provided for convenience.
68pub trait SimdFrom<T, S: Simd> {
69    fn simd_from(simd: S, value: T) -> Self;
70}
71
72/// Value conversion, adding a SIMD blessing.
73///
74/// This trait is syntactic sugar for [`SimdFrom`] and exists only to allow
75/// `impl SimdInto` syntax in signatures, which would otherwise require
76/// cumbersome `where` clauses in terms of `SimdFrom`.
77///
78/// Avoid implementing this trait directly, prefer implementing [`SimdFrom`].
79pub trait SimdInto<T, S> {
80    fn simd_into(self, simd: S) -> T;
81}
82
83impl<F, T: SimdFrom<F, S>, S: Simd> SimdInto<T, S> for F {
84    fn simd_into(self, simd: S) -> T {
85        SimdFrom::simd_from(simd, self)
86    }
87}
88
89impl<T, S: Simd> SimdFrom<T, S> for T {
90    fn simd_from(_simd: S, value: T) -> Self {
91        value
92    }
93}
94
95/// Types that can be used as elements in SIMD vectors.
96pub trait SimdElement {
97    /// The associated mask lane type. This will be a signed integer of the same size as this type.
98    type Mask: SimdElement;
99}
100
101impl SimdElement for f32 {
102    type Mask = i32;
103}
104
105impl SimdElement for f64 {
106    type Mask = i64;
107}
108
109impl SimdElement for u8 {
110    type Mask = i8;
111}
112
113impl SimdElement for i8 {
114    type Mask = Self;
115}
116
117impl SimdElement for u16 {
118    type Mask = i16;
119}
120
121impl SimdElement for i16 {
122    type Mask = Self;
123}
124
125impl SimdElement for u32 {
126    type Mask = i32;
127}
128
129impl SimdElement for i32 {
130    type Mask = Self;
131}
132
133impl SimdElement for i64 {
134    type Mask = Self;
135}
136
137/// Construction of integer vectors from floats by truncation
138pub trait SimdCvtTruncate<T> {
139    fn truncate_from(x: T) -> Self;
140    fn truncate_from_precise(x: T) -> Self;
141}
142
143/// Construction of floating point vectors from integers
144pub trait SimdCvtFloat<T> {
145    fn float_from(x: T) -> Self;
146}
147
148/// Concatenation of two SIMD vectors.
149///
150/// This is implemented on all vectors 256 bits and lower, producing vectors of up to 512 bits.
151pub trait SimdCombine<S: Simd>: SimdBase<S> {
152    type Combined: SimdBase<S, Element = Self::Element, Block = Self::Block>;
153
154    /// Concatenate two vectors into a new one that's twice as long.
155    fn combine(self, rhs: impl SimdInto<Self, S>) -> Self::Combined;
156}
157
158/// Splitting of one SIMD vector into two.
159///
160/// This is implemented on all vectors 256 bits and higher, producing vectors of down to 128 bits.
161pub trait SimdSplit<S: Simd>: SimdBase<S> {
162    type Split: SimdBase<S, Element = Self::Element, Block = Self::Block>;
163
164    /// Split this vector into left and right halves.
165    fn split(self) -> (Self::Split, Self::Split);
166}