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}