mirror of
https://github.com/github/codeql.git
synced 2026-07-08 21:15:32 +02:00
yeast: Implement IntoIterator for Id as a singleton
There's an awkward divide in yeast between returning a list of nodes or optional node (both of which are iterable), and returning a single node (which is not). In practice, we would like all of these cases to be handled transparently: if a single node is returned, it behaves as if it were a singleton list containing that node. This gives us a uniform interface during translation -- no matter what is returned, it will be an iterable of nodes. To facilitate this, we make the slightly unorthodox choice of implementing IntoIterator for Id, with the behaviour detailed above.
This commit is contained in:
@@ -26,6 +26,12 @@ use query::QueryNode;
|
||||
/// without colliding with the impls for plain integers.
|
||||
///
|
||||
/// Use `id.0` (or `id.into()`) to obtain the raw arena index.
|
||||
///
|
||||
/// Implements [`IntoIterator`] as a singleton (`iter::once(self)`)
|
||||
/// so that a bare `Id` can be used interchangeably with `Option<Id>`
|
||||
/// / `Vec<Id>` in places that expect an iterable of ids (e.g.
|
||||
/// [`crate::build::BuildCtx::translate`] and the field-splice
|
||||
/// interpolation via [`IntoFieldIds`]).
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Serialize)]
|
||||
pub struct Id(pub usize);
|
||||
@@ -42,6 +48,14 @@ impl From<Id> for usize {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Id {
|
||||
type Item = Id;
|
||||
type IntoIter = std::iter::Once<Id>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
std::iter::once(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Field and Kind ids are provided by tree-sitter
|
||||
type FieldId = u16;
|
||||
type KindId = u16;
|
||||
@@ -49,9 +63,10 @@ type KindId = u16;
|
||||
/// Trait for values that can be appended to a field's id list inside a
|
||||
/// `tree!`/`trees!`/`rule!` template (in `{expr}` placeholders).
|
||||
///
|
||||
/// `Id` pushes a single id; the blanket impl for
|
||||
/// `IntoIterator<Item: Into<Id>>` handles `Vec<Id>`, `Option<Id>`,
|
||||
/// arbitrary iterators yielding `Id`, etc.
|
||||
/// The blanket impl for `IntoIterator<Item: Into<Id>>` handles all
|
||||
/// current shapes: `Vec<Id>`, `Option<Id>`, arbitrary iterators
|
||||
/// yielding `Id`, and a bare `Id` itself (which is `IntoIterator`
|
||||
/// via a singleton).
|
||||
///
|
||||
/// This lets `{expr}` interpolate any of these shapes without a
|
||||
/// dedicated splice syntax — the macro emits the same trait-dispatched
|
||||
@@ -60,12 +75,6 @@ pub trait IntoFieldIds {
|
||||
fn extend_into(self, out: &mut Vec<Id>);
|
||||
}
|
||||
|
||||
impl IntoFieldIds for Id {
|
||||
fn extend_into(self, out: &mut Vec<Id>) {
|
||||
out.push(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T> IntoFieldIds for I
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
|
||||
Reference in New Issue
Block a user