Skip to main content

yume_pdq/kernel/
type_traits.rs

1/*
2 * Copyright (c) 2025 Yumechi <yume@yumechi.jp>
3 *
4 * Created on Thursday, March 27, 2025
5 * Author: Yumechi <yume@yumechi.jp>
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22use core::{
23    fmt::Debug,
24    marker::PhantomData,
25    ops::{BitAnd, BitOr, Mul},
26};
27
28#[allow(unused_imports)]
29use crate::alignment::AlignerTo;
30use generic_array::{
31    ArrayLength,
32    typenum::{B0, B1, Bit, UInt},
33};
34use kernel_sealing::KernelSealed;
35
36mod sealing {
37    pub trait Sealed {}
38}
39
40impl<U, B: Bit> sealing::Sealed for UInt<U, B> {}
41
42/// A type-level LUT for squaring a number.
43///
44/// Currently it is defined for up to 1024x1024 (the implementors are hidden from rustdoc).
45pub trait SquareOf: ArrayLength + sealing::Sealed {
46    /// The Squared result type.
47    type Output: ArrayLength;
48}
49
50include!(concat!(env!("OUT_DIR"), "/square_generic_array.rs"));
51
52/// Whether a number is divisible by 8.
53pub trait DivisibleBy8: ArrayLength + sealing::Sealed
54where
55    <Self::Output as Mul<Self>>::Output: ArrayLength,
56{
57    /// The result after dividing by 8.
58    type Output: ArrayLength + Mul<Self>;
59}
60
61impl<U: ArrayLength> DivisibleBy8 for UInt<UInt<UInt<U, B0>, B0>, B0>
62where
63    U: Mul<UInt<UInt<UInt<U, B0>, B0>, B0>>,
64    <U as Mul<UInt<UInt<UInt<U, B0>, B0>, B0>>>::Output: ArrayLength,
65{
66    type Output = U;
67}
68
69pub(crate) mod kernel_sealing {
70    pub trait KernelSealed {}
71}
72
73/// Type level struct to represent the compiler time requirements for a kernel.
74pub struct RequireCompilerTimeHardwareFeature<Cur, Next> {
75    _cur: PhantomData<Cur>,
76    _next: PhantomData<Next>,
77}
78
79impl<S: KernelSealed, N: KernelSealed> KernelSealed for RequireCompilerTimeHardwareFeature<S, N> {}
80
81/// Type level struct to represent a hardware feature guarded by a fallback that is guaranteed to be available.
82pub struct FallbackRequirements<S: KernelSealed, N: KernelSealed> {
83    _preferred: PhantomData<S>,
84    _fallback: PhantomData<N>,
85}
86
87impl<S: KernelSealed, N: KernelSealed> KernelSealed for FallbackRequirements<S, N> {}
88
89/// Type level trait to represent the runtime requirements for a kernel.
90pub trait EvaluateHardwareFeature: KernelSealed {
91    /// Whether the feature is possible to use at compile time.
92    type EnabledStatic: Bit + BitOr<B0> + BitAnd<B1> + BitOr<B1> + BitAnd<B0>;
93    /// Whether the feature must be checked before execution at runtime.
94    type MustCheck: Bit;
95    /// The name of the feature.
96    type Name: Debug + Clone + Copy + 'static + PartialEq;
97
98    /// Get the name of the requirement.
99    fn name() -> Self::Name;
100
101    /// Check if the feature is available at runtime.
102    fn met_runtime() -> bool;
103}
104
105#[derive(Debug, Clone, Copy, PartialEq)]
106/// A type that represents the intersection of two names.
107pub struct AndName<A, B>(A, B);
108
109impl<F: EvaluateHardwareFeature, N: EvaluateHardwareFeature> EvaluateHardwareFeature
110    for RequireCompilerTimeHardwareFeature<F, N>
111where
112    <F as EvaluateHardwareFeature>::EnabledStatic:
113        BitAnd<<N as EvaluateHardwareFeature>::EnabledStatic>,
114    <F::EnabledStatic as BitAnd<N::EnabledStatic>>::Output: Bit,
115    <F as EvaluateHardwareFeature>::MustCheck: BitOr<<N as EvaluateHardwareFeature>::MustCheck>,
116    <F::MustCheck as BitOr<N::MustCheck>>::Output: Bit,
117    <<F as EvaluateHardwareFeature>::EnabledStatic as BitAnd<
118        <N as EvaluateHardwareFeature>::EnabledStatic,
119    >>::Output: BitAnd<B0>,
120    <<F as EvaluateHardwareFeature>::EnabledStatic as BitAnd<
121        <N as EvaluateHardwareFeature>::EnabledStatic,
122    >>::Output: BitAnd<B0>,
123    <<F as EvaluateHardwareFeature>::EnabledStatic as BitAnd<
124        <N as EvaluateHardwareFeature>::EnabledStatic,
125    >>::Output: BitAnd<B0>,
126    <<F as EvaluateHardwareFeature>::EnabledStatic as BitAnd<
127        <N as EvaluateHardwareFeature>::EnabledStatic,
128    >>::Output: BitOr<B1>,
129    <<F as EvaluateHardwareFeature>::EnabledStatic as BitAnd<
130        <N as EvaluateHardwareFeature>::EnabledStatic,
131    >>::Output: BitAnd<B1>,
132    <<F as EvaluateHardwareFeature>::EnabledStatic as BitAnd<
133        <N as EvaluateHardwareFeature>::EnabledStatic,
134    >>::Output: BitOr<B0>,
135{
136    type Name = AndName<F::Name, N::Name>;
137    type EnabledStatic = <F::EnabledStatic as BitAnd<N::EnabledStatic>>::Output;
138    type MustCheck = <F::MustCheck as BitOr<N::MustCheck>>::Output;
139
140    fn name() -> Self::Name {
141        AndName(F::name(), N::name())
142    }
143
144    fn met_runtime() -> bool {
145        F::met_runtime() && N::met_runtime()
146    }
147}
148
149#[derive(Debug, Clone, Copy, PartialEq)]
150/// A type that represents the union of two names.
151pub struct FallbackName<A, B>(A, B);
152
153impl<P: EvaluateHardwareFeature, F: EvaluateHardwareFeature<EnabledStatic = B1>>
154    EvaluateHardwareFeature for FallbackRequirements<P, F>
155{
156    type Name = FallbackName<P::Name, F::Name>;
157    type EnabledStatic = B1;
158    type MustCheck = B0;
159
160    fn name() -> Self::Name {
161        FallbackName(P::name(), F::name())
162    }
163
164    fn met_runtime() -> bool {
165        P::met_runtime()
166    }
167}
168
169impl EvaluateHardwareFeature for Term {
170    type Name = &'static str;
171    type EnabledStatic = B1;
172    type MustCheck = B0;
173
174    fn name() -> Self::Name {
175        "."
176    }
177
178    fn met_runtime() -> bool {
179        true
180    }
181}
182
183/// A type that represents a kernel that is always available.
184pub struct Term {
185    _private: (),
186}
187
188impl KernelSealed for Term {}
189
190#[cfg(test)]
191mod tests {
192    #![allow(dead_code, unused)]
193
194    use generic_array::typenum::{U7, U9, U56, U81};
195
196    use super::*;
197
198    type TestSquareOf9 = <U9 as SquareOf>::Output;
199    type ExpectedSquareOf9 = U81;
200    type Test56DivisibleBy8 = <U56 as DivisibleBy8>::Output;
201    type Expected56DivisibleBy8 = U7;
202    const ASSERT_SQUARE_OF_9_IS_U81: PhantomData<ExpectedSquareOf9> = PhantomData::<TestSquareOf9>;
203    const ASSERT_56_DIVISIBLE_BY_8_IS_U7: PhantomData<Expected56DivisibleBy8> =
204        PhantomData::<Test56DivisibleBy8>;
205}