marker_api/ast/generic.rs
1use std::fmt::Debug;
2use std::marker::PhantomData;
3
4mod args;
5pub use args::*;
6mod param;
7pub use param::*;
8
9use crate::{
10 common::{GenericId, SpanId, SymbolId},
11 context::with_cx,
12 ffi::{FfiOption, FfiSlice},
13 span::Span,
14};
15
16/// A lifetime used as a generic argument or on a reference like this:
17///
18/// ```
19/// # use core::marker::PhantomData;
20/// # #[derive(Default)]
21/// # struct Item<'a> {
22/// # _data: PhantomData<&'a ()>,
23/// # }
24///
25/// # fn example<'a>() {
26/// let _item: Item<'_> = Item::default();
27/// // ^^
28/// let _item: Item<'a> = Item::default();
29/// // ^^
30/// let _item: &'static str = "Hello world";
31/// // ^^^^^^^
32/// # }
33/// ```
34#[repr(C)]
35#[derive(Debug)]
36pub struct Lifetime<'ast> {
37 #[allow(clippy::struct_field_names)]
38 _lifetime: PhantomData<&'ast ()>,
39 span: FfiOption<SpanId>,
40 kind: LifetimeKind,
41}
42
43#[repr(C)]
44#[derive(Debug)]
45#[allow(clippy::exhaustive_enums)]
46#[cfg_attr(feature = "driver-api", visibility::make(pub))]
47pub(crate) enum LifetimeKind {
48 /// A lifetime with a label like `'ast`
49 Label(SymbolId, GenericId),
50 /// The magic `'static` lifetime
51 Static,
52 /// The mysterious `'_` lifetime
53 Infer,
54}
55
56impl<'ast> Lifetime<'ast> {
57 /// This returns the [`GenericId`] of this lifetime, if it's labeled, or [`None`]
58 /// otherwise. `'static` will also return [`None`]
59 pub fn id(&self) -> Option<GenericId> {
60 match self.kind {
61 LifetimeKind::Label(_, id) => Some(id),
62 _ => None,
63 }
64 }
65
66 /// Note that the `'static` lifetime is not a label and will therefore return [`None`]
67 pub fn label(&self) -> Option<&str> {
68 match self.kind {
69 LifetimeKind::Label(sym, _) => Some(with_cx(self, |cx| cx.symbol_str(sym))),
70 _ => None,
71 }
72 }
73
74 pub fn has_label(&self) -> bool {
75 matches!(self.kind, LifetimeKind::Label(..))
76 }
77
78 pub fn is_static(&self) -> bool {
79 matches!(self.kind, LifetimeKind::Static)
80 }
81
82 pub fn is_infer(&self) -> bool {
83 matches!(self.kind, LifetimeKind::Infer)
84 }
85
86 pub fn span(&self) -> Option<&Span<'ast>> {
87 self.span.get().map(|span| with_cx(self, |cx| cx.span(*span)))
88 }
89}
90
91#[cfg(feature = "driver-api")]
92impl<'ast> Lifetime<'ast> {
93 pub fn new(span: Option<SpanId>, kind: LifetimeKind) -> Self {
94 Self {
95 _lifetime: PhantomData,
96 span: span.into(),
97 kind,
98 }
99 }
100}
101
102/// The syntactic representation of generic arguments for an item or path.
103///
104/// ```
105/// # use std::fmt::Debug;
106/// // vv This is a generic argument
107/// generic_item::<u8>(32);
108///
109/// pub fn generic_item<T: Copy>(t: T)
110/// // ^^^^^^^ This is a generic parameter
111/// where
112/// T: Debug,
113/// // ^^^^^^^^ This is a bound for a generic parameter
114/// {
115/// println!("{:#?}", t);
116/// }
117/// ```
118///
119/// See:
120/// * [`GenericParams`]
121#[repr(C)]
122#[derive(Debug)]
123#[cfg_attr(feature = "driver-api", derive(Clone))]
124pub struct GenericArgs<'ast> {
125 args: FfiSlice<'ast, GenericArgKind<'ast>>,
126}
127
128impl<'ast> GenericArgs<'ast> {
129 pub fn args(&self) -> &'ast [GenericArgKind<'ast>] {
130 self.args.get()
131 }
132
133 pub fn is_empty(&self) -> bool {
134 self.args.is_empty()
135 }
136}
137
138#[cfg(feature = "driver-api")]
139impl<'ast> GenericArgs<'ast> {
140 pub fn new(args: &'ast [GenericArgKind<'ast>]) -> Self {
141 Self { args: args.into() }
142 }
143}
144
145/// A singular generic argument.
146///
147/// See: <https://doc.rust-lang.org/stable/reference/paths.html>
148#[repr(C)]
149#[non_exhaustive]
150#[derive(Debug)]
151#[cfg_attr(feature = "driver-api", derive(Clone))]
152pub enum GenericArgKind<'ast> {
153 /// A lifetime as a generic argument, like this:
154 ///
155 /// ```
156 /// # use std::marker::PhantomData;
157 /// # #[derive(Default)]
158 /// # pub struct HasLifetime<'a> {
159 /// # _data: PhantomData<&'a ()>,
160 /// # }
161 /// let _foo: HasLifetime<'static> = HasLifetime::default();
162 /// // ^^^^^^^
163 /// ```
164 Lifetime(&'ast LifetimeArg<'ast>),
165 /// A type as a generic argument, like this:
166 ///
167 /// ```
168 /// let _bar: Vec<String> = vec![];
169 /// // ^^^^^^
170 /// ```
171 Ty(&'ast TyArg<'ast>),
172 /// A type binding as a generic argument, like this:
173 ///
174 /// ```ignore
175 /// let _baz: &dyn Iterator<Item=String> = todo!();
176 /// // ^^^^^^^^^^^
177 /// ```
178 Binding(&'ast BindingArg<'ast>),
179 /// A constant expression as a generic argument, like this:
180 ///
181 /// ```ignore
182 /// # struct Vec<const N: usize> {
183 /// # data: [f32; N],
184 /// # }
185 /// #
186 /// let _bat: Vec<3> = todo!();
187 /// // ^
188 /// ```
189 Const(&'ast ConstArg<'ast>),
190}
191
192/// This represents the generic parameters of a generic item. The bounds applied
193/// to the parameters in the declaration are stored as clauses in this struct.
194///
195/// ```
196/// # use std::fmt::Debug;
197/// pub fn generic_item<T: Copy>(t: T)
198/// // ^^^^^^^ This is a generic parameter
199/// where
200/// T: Debug,
201/// // ^^^^^^^^ This is a bound for a generic parameter
202/// {
203/// println!("{:#?}", t);
204/// }
205///
206/// // vv This is a generic argument
207/// generic_item::<u8>(32);
208/// ```
209/// See
210/// * [`GenericArgs`]
211#[repr(C)]
212#[derive(Debug)]
213pub struct GenericParams<'ast> {
214 params: FfiSlice<'ast, GenericParamKind<'ast>>,
215 clauses: FfiSlice<'ast, WhereClauseKind<'ast>>,
216}
217
218impl<'ast> GenericParams<'ast> {
219 pub fn params(&self) -> &'ast [GenericParamKind<'ast>] {
220 self.params.get()
221 }
222
223 pub fn clauses(&self) -> &'ast [WhereClauseKind<'ast>] {
224 self.clauses.get()
225 }
226}
227
228#[cfg(feature = "driver-api")]
229impl<'ast> GenericParams<'ast> {
230 pub fn new(params: &'ast [GenericParamKind<'ast>], clauses: &'ast [WhereClauseKind<'ast>]) -> Self {
231 Self {
232 params: params.into(),
233 clauses: clauses.into(),
234 }
235 }
236}