Skip to content

Commit 8272848

Browse files
committed
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.
1 parent 3c3f740 commit 8272848

1 file changed

Lines changed: 18 additions & 9 deletions

File tree

shared/yeast/src/lib.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ use query::QueryNode;
2626
/// without colliding with the impls for plain integers.
2727
///
2828
/// Use `id.0` (or `id.into()`) to obtain the raw arena index.
29+
///
30+
/// Implements [`IntoIterator`] as a singleton (`iter::once(self)`)
31+
/// so that a bare `Id` can be used interchangeably with `Option<Id>`
32+
/// / `Vec<Id>` in places that expect an iterable of ids (e.g.
33+
/// [`crate::build::BuildCtx::translate`] and the field-splice
34+
/// interpolation via [`IntoFieldIds`]).
2935
#[repr(transparent)]
3036
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Serialize)]
3137
pub struct Id(pub usize);
@@ -42,16 +48,25 @@ impl From<Id> for usize {
4248
}
4349
}
4450

51+
impl IntoIterator for Id {
52+
type Item = Id;
53+
type IntoIter = std::iter::Once<Id>;
54+
fn into_iter(self) -> Self::IntoIter {
55+
std::iter::once(self)
56+
}
57+
}
58+
4559
/// Field and Kind ids are provided by tree-sitter
4660
type FieldId = u16;
4761
type KindId = u16;
4862

4963
/// Trait for values that can be appended to a field's id list inside a
5064
/// `tree!`/`trees!`/`rule!` template (in `{expr}` placeholders).
5165
///
52-
/// `Id` pushes a single id; the blanket impl for
53-
/// `IntoIterator<Item: Into<Id>>` handles `Vec<Id>`, `Option<Id>`,
54-
/// arbitrary iterators yielding `Id`, etc.
66+
/// The blanket impl for `IntoIterator<Item: Into<Id>>` handles all
67+
/// current shapes: `Vec<Id>`, `Option<Id>`, arbitrary iterators
68+
/// yielding `Id`, and a bare `Id` itself (which is `IntoIterator`
69+
/// via a singleton).
5570
///
5671
/// This lets `{expr}` interpolate any of these shapes without a
5772
/// dedicated splice syntax — the macro emits the same trait-dispatched
@@ -60,12 +75,6 @@ pub trait IntoFieldIds {
6075
fn extend_into(self, out: &mut Vec<Id>);
6176
}
6277

63-
impl IntoFieldIds for Id {
64-
fn extend_into(self, out: &mut Vec<Id>) {
65-
out.push(self);
66-
}
67-
}
68-
6978
impl<I, T> IntoFieldIds for I
7079
where
7180
I: IntoIterator<Item = T>,

0 commit comments

Comments
 (0)