proc_macro_assertions/generatable/
mod.rs

1mod r#trait;
2mod r#type;
3
4use std::hash::Hash;
5use std::ops::{Deref, DerefMut};
6
7use better_any::{Tid, TidAble};
8use quote::ToTokens;
9pub use r#trait::Trait;
10pub use r#type::Type;
11
12use proc_macro2::TokenStream;
13
14use crate::maybe_borrowed::MaybeBorrowed;
15
16use super::{context::Context, passed_data::PassedData};
17
18/// This indicates that some type can be turned into tokens that assert something.
19/// Be aware that this only relies on rust's type checking, the code that is generated
20/// is never actually meant to be executed. The generation functions in three distinct "Stages".
21/// See below for more information on that.
22///
23///
24/// The type implementing this must also be [`TidAble`], which is similar to [`Any`](std::any::Any)
25/// but allows for non-'static lifetimes. The easiest way to implement it is to use the derive macro (`#[derive(Tid)]`)
26///
27/// # Idents
28/// There is a need to ensure that there are no ident collisions among the generated code.
29/// For that purpose in each stage there is a context provided, which contains some [`IdentGenerator`](crate::ident_generator::IdentGenerator).
30/// Other than Idents passed into the methods by either `Self` or any parameters, use Idents generates by the `IdentGenerator`
31/// exclusively to avoid any collisions.
32///
33/// # Generation "Stages"
34/// ## Stage 1: Generatable
35/// These tokens are generated for each type that implemets this trait once. This is the perfect place to put
36/// tokens that are needed as "Setup" for any asserts.
37/// ## Stage 2: Template
38/// These tokens are generated for each unique instance of `Self`. You should put any tokens that should be unique
39/// for each instance in here.
40/// ## Stage 3: Assert
41/// These tokens are generated for each unique Assert, which represent some type that is tested against `Self`.
42/// No generation is actually happening until at least one assert is created for `Self`.
43///
44/// # Passed Data
45/// There may be a need to pass data, for example generated idents, between stages. For that purpose
46/// this trait provides a way to do so. See [`PassedData`](crate::passed_data::PassedData) for more information.
47pub trait Generatable<'a, Assert>
48where
49    Self: TidAble<'a>,
50    Assert: 'a + TidAble<'a>,
51{
52    /// The type of any data passed from the `Generatable` stage to proceeding stages.
53    type GeneratableData: 'a;
54    /// The type of any data passed from the `Template` stage to proceeding stages.
55    type TemplateData: 'a;
56
57    /// Set this to true when any of the emitted code may be non-constant
58    const EMITS_NON_CONSTANT_CODE: bool;
59
60    /// This is the method the `Generatable` stage is composed of. Should return Tokens (if any) generated by this stage,
61    /// plus optionally any data passed to preceding stages.
62    fn generatable(context: &mut Context) -> PassedData<Self::GeneratableData>
63    where
64        Self: Sized;
65
66    /// This is the method the `Template` stage is composed of. Should return Tokens (if any) generated by this stage,
67    /// plus optionally any data passed to preceding stages.
68    fn template(
69        &self,
70        context: &mut Context,
71        passed: &Self::GeneratableData,
72    ) -> PassedData<Self::TemplateData>;
73
74    /// This is the method the `Assert` stage is composed of. Should return Tokens generated by this stage.
75    fn assert(
76        &self,
77        _context: &mut Context,
78        _passed: (&Self::GeneratableData, &Self::TemplateData),
79        _to_assert: &Assert,
80    ) -> Option<TokenStream>;
81}
82
83#[derive(Tid)]
84#[repr(transparent)]
85pub struct StaticTid<T: 'static>(pub T);
86
87impl<T: 'static> From<T> for StaticTid<T> {
88    fn from(value: T) -> Self {
89        Self(value)
90    }
91}
92
93impl<'a, T> From<&'a T> for &'a StaticTid<T> {
94    fn from(value: &'a T) -> Self {
95        // Safe because StaticTid is #[repr(transparent)].
96        unsafe { &*(value as *const T).cast::<StaticTid<T>>() }
97    }
98}
99
100impl<'a, T> From<&'a mut T> for &'a mut StaticTid<T> {
101    fn from(value: &'a mut T) -> Self {
102        // Safe because StaticTid is #[repr(transparent)].
103        unsafe { &mut *(value as *mut T).cast::<StaticTid<T>>() }
104    }
105}
106
107impl<'a, U> From<&'a U> for MaybeBorrowed<'a, StaticTid<U>> {
108    fn from(value: &'a U) -> Self {
109        MaybeBorrowed::Borrowed(value.into())
110    }
111}
112
113impl<'a, T> From<T> for MaybeBorrowed<'a, StaticTid<T>> {
114    fn from(value: T) -> Self {
115        MaybeBorrowed::Owned(StaticTid(value))
116    }
117}
118impl<T: 'static> Deref for StaticTid<T> {
119    type Target = T;
120
121    fn deref(&self) -> &Self::Target {
122        &self.0
123    }
124}
125
126impl<T: 'static> DerefMut for StaticTid<T> {
127    fn deref_mut(&mut self) -> &mut Self::Target {
128        &mut self.0
129    }
130}
131
132impl<T: 'static + ToTokens> ToTokens for StaticTid<T> {
133    fn to_tokens(&self, tokens: &mut TokenStream) {
134        (**self).to_tokens(tokens);
135    }
136}
137
138impl<T: 'static + PartialEq> PartialEq for StaticTid<T> {
139    fn eq(&self, other: &Self) -> bool {
140        (**self).eq(&**other)
141    }
142}
143
144impl<T: 'static + Eq> Eq for StaticTid<T> {}
145
146impl<T: 'static + PartialOrd> PartialOrd for StaticTid<T> {
147    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
148        (**self).partial_cmp(&**other)
149    }
150}
151
152impl<T: 'static + Ord> Ord for StaticTid<T> {
153    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
154        (**self).cmp(&**other)
155    }
156}
157
158impl<T: 'static + Hash> Hash for StaticTid<T> {
159    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
160        (**self).hash(state);
161    }
162}