Skip to content

Commit 57afd7c

Browse files
authored
Merge pull request #3822 from froydnj/froydnj-vec-first-last
[rust] implement `first`/`last` on vector-like things
2 parents 4c79365 + 6b9674e commit 57afd7c

File tree

1 file changed

+56
-9
lines changed

1 file changed

+56
-9
lines changed

rust/ruby-prism/src/lib.rs

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ pub struct NodeList<'pr> {
139139
}
140140

141141
impl<'pr> NodeList<'pr> {
142+
unsafe fn at(&self, index: usize) -> Node<'pr> {
143+
let node: *mut pm_node_t = *(self.pointer.as_ref().nodes.add(index));
144+
Node::new(self.parser, node)
145+
}
146+
142147
/// Returns an iterator over the nodes.
143148
#[must_use]
144149
pub const fn iter(&self) -> NodeListIter<'pr> {
@@ -161,6 +166,26 @@ impl<'pr> NodeList<'pr> {
161166
pub const fn is_empty(&self) -> bool {
162167
self.len() == 0
163168
}
169+
170+
/// Returns the first element of the list, or `None` if it is empty.
171+
#[must_use]
172+
pub fn first(&self) -> Option<Node<'pr>> {
173+
if self.is_empty() {
174+
None
175+
} else {
176+
Some(unsafe { self.at(0) })
177+
}
178+
}
179+
180+
/// Returns the last element of the list, or `None` if it is empty.
181+
#[must_use]
182+
pub fn last(&self) -> Option<Node<'pr>> {
183+
if self.is_empty() {
184+
None
185+
} else {
186+
Some(unsafe { self.at(self.len() - 1) })
187+
}
188+
}
164189
}
165190

166191
impl<'pr> IntoIterator for &NodeList<'pr> {
@@ -245,6 +270,11 @@ pub struct ConstantList<'pr> {
245270
}
246271

247272
impl<'pr> ConstantList<'pr> {
273+
const unsafe fn at(&self, index: usize) -> ConstantId<'pr> {
274+
let constant_id: pm_constant_id_t = *(self.pointer.as_ref().ids.add(index));
275+
ConstantId::new(self.parser, constant_id)
276+
}
277+
248278
/// Returns an iterator over the constants in the list.
249279
#[must_use]
250280
pub const fn iter(&self) -> ConstantListIter<'pr> {
@@ -267,6 +297,26 @@ impl<'pr> ConstantList<'pr> {
267297
pub const fn is_empty(&self) -> bool {
268298
self.len() == 0
269299
}
300+
301+
/// Returns the first element of the list, or `None` if it is empty.
302+
#[must_use]
303+
pub const fn first(&self) -> Option<ConstantId<'pr>> {
304+
if self.is_empty() {
305+
None
306+
} else {
307+
Some(unsafe { self.at(0) })
308+
}
309+
}
310+
311+
/// Returns the last element of the list, or `None` if it is empty.
312+
#[must_use]
313+
pub const fn last(&self) -> Option<ConstantId<'pr>> {
314+
if self.is_empty() {
315+
None
316+
} else {
317+
Some(unsafe { self.at(self.len() - 1) })
318+
}
319+
}
270320
}
271321

272322
impl<'pr> IntoIterator for &ConstantList<'pr> {
@@ -815,31 +865,28 @@ mod tests {
815865

816866
#[test]
817867
fn constant_id_test() {
818-
let source = "module Foo; x = 1; end";
868+
let source = "module Foo; x = 1; y = 2; end";
819869
let result = parse(source.as_ref());
820870

821871
let node = result.node();
822872
assert_eq!(node.as_program_node().unwrap().statements().body().len(), 1);
823873
assert!(!node.as_program_node().unwrap().statements().body().is_empty());
824-
let module = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
874+
let module = node.as_program_node().and_then(|pn| pn.statements().body().first()).unwrap();
825875
let module = module.as_module_node().unwrap();
826876

827-
assert_eq!(module.locals().len(), 1);
877+
assert_eq!(module.locals().len(), 2);
828878
assert!(!module.locals().is_empty());
829879

830-
let locals = module.locals().iter().collect::<Vec<_>>();
831-
832-
assert_eq!(locals.len(), 1);
833-
834-
assert_eq!(locals[0].as_slice(), b"x");
880+
assert_eq!(module.locals().first().unwrap().as_slice(), b"x");
881+
assert_eq!(module.locals().last().unwrap().as_slice(), b"y");
835882

836883
let source = "module Foo; end";
837884
let result = parse(source.as_ref());
838885

839886
let node = result.node();
840887
assert_eq!(node.as_program_node().unwrap().statements().body().len(), 1);
841888
assert!(!node.as_program_node().unwrap().statements().body().is_empty());
842-
let module = node.as_program_node().unwrap().statements().body().iter().next().unwrap();
889+
let module = node.as_program_node().and_then(|pn| pn.statements().body().first()).unwrap();
843890
let module = module.as_module_node().unwrap();
844891

845892
assert_eq!(module.locals().len(), 0);

0 commit comments

Comments
 (0)