Skip to content

Commit a467dbd

Browse files
committed
Implement IntoIterator for Vector
1 parent bece796 commit a467dbd

File tree

7 files changed

+91
-34
lines changed

7 files changed

+91
-34
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55

66
## [Unreleased]
7+
- Reworked `Vector`, making it iterable.
78

89
## [0.13.0] - 2020-03-11
910
- Added `GlobalRef`, which allows keeping Lisp values around without an `Env`.

guide/src/calling-lisp.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ env.call("add-hook", [
5050
#[defun]
5151
fn listify_vec(vector: Vector) -> Result<Value> {
5252
let mut args = vec![];
53-
for i in 0..vector.size()? {
54-
args.push(vector.get(i)?)
53+
for e in vector {
54+
args.push(e)
5555
}
5656
vector.0.env.call("list", &args)
5757
}

guide/src/functions.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ Each parameter must be one of the following:
3434
#[defun(user_ptr)]
3535
fn to_rust_vec_string(input: Vector) -> Result<Vec<String>> {
3636
let mut vec = vec![];
37-
for i in 0..input.size()? {
38-
vec.push(input.get(i)?.into_rust()?);
37+
for e in input {
38+
vec.push(e.into_rust()?);
3939
}
4040
Ok(vec)
4141
}

src/call.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ impl<'e> Value<'e> {
2525
/// # use emacs::{defun, Value, Result, Vector};
2626
/// #[defun]
2727
/// fn mapc_enumerate_vec(function: Value, vector: Vector) -> Result<()> {
28-
/// for nth in 0..vector.size()? {
29-
/// let elem: Value = vector.get(nth)?;
28+
/// for (nth, elem) in vector.into_iter().enumerate() {
3029
/// function.call((nth, elem))?;
3130
/// }
3231
/// Ok(())
@@ -65,10 +64,10 @@ impl Env {
6564
/// # use emacs::{defun, Value, Result, Vector};
6665
/// #[defun]
6766
/// fn listify_vec(vector: Vector) -> Result<Value> {
68-
/// let env = vector.0.env;
67+
/// let env = vector.value().env;
6968
/// let mut args = vec![];
70-
/// for i in 0..vector.size()? {
71-
/// args.push(vector.get(i)?)
69+
/// for elem in vector {
70+
/// args.push(elem)
7271
/// }
7372
/// env.call("list", &args)
7473
/// }

src/types/vector.rs

Lines changed: 78 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ use std::convert::TryInto;
33
use super::*;
44
use crate::{subr, call::IntoLispArgs};
55

6-
/// A type that represents Lisp vectors. This is a newtype wrapper around [`Value`] that provides
6+
/// A type that represents Lisp vectors. This is a wrapper around [`Value`] that provides
77
/// vector-specific methods.
88
///
9-
/// Arguments to #[[`defun`]] having this type will be type-checked. This type checking can be
10-
/// omitted by manually wrapping a [`Value`]. Note that Emacs still does type checking when calling
11-
/// methods on the vector.
9+
/// Arguments to #[[`defun`]] having this type will be type-checked. If you want to omit, or delay
10+
/// this type checking, use [`Value`] instead.
1211
///
1312
/// ```
1413
/// use emacs::{defun, Value, Vector, Result};
@@ -20,62 +19,121 @@ use crate::{subr, call::IntoLispArgs};
2019
///
2120
/// #[defun]
2221
/// fn no_type_check(value: Value) -> Result<Vector> {
23-
/// Ok(Vector(value))
22+
/// Ok(Vector::from_value_unchecked(value, 0))
2423
/// }
2524
/// ```
2625
///
2726
/// [`Value`]: struct.Value.html
2827
/// [`defun`]: attr.defun.html
2928
#[derive(Debug, Clone, Copy)]
30-
pub struct Vector<'e>(pub Value<'e>);
29+
pub struct Vector<'e> {
30+
value: Value<'e>,
31+
len: usize,
32+
}
3133

3234
impl<'e> Vector<'e> {
35+
#[doc(hidden)]
36+
#[inline]
37+
pub fn from_value_unchecked(value: Value<'e>, len: usize) -> Self {
38+
Self { value, len }
39+
}
40+
3341
pub fn get<T: FromLisp<'e>>(&self, i: usize) -> Result<T> {
34-
let v = self.0;
42+
let v = self.value;
3543
let env = v.env;
3644
// Safety: Same lifetime. Emacs does bound checking.
3745
unsafe_raw_call_value!(env, vec_get, v.raw, i as isize)?.into_rust()
3846
}
3947

4048
pub fn set<T: IntoLisp<'e>>(&self, i: usize, value: T) -> Result<()> {
41-
let v = self.0;
49+
let v = self.value;
4250
let env = v.env;
4351
let value = value.into_lisp(env)?;
4452
// Safety: Same lifetime. Emacs does bound checking.
4553
unsafe_raw_call!(env, vec_set, v.raw, i as isize, value.raw)
4654
}
4755

56+
#[deprecated(since = "0.14.0", note = "Use .len() instead")]
57+
#[doc(hidden)]
4858
pub fn size(&self) -> Result<usize> {
49-
let v = self.0;
50-
let env = v.env;
51-
let result =
52-
unsafe_raw_call_no_exit!(env, vec_size, v.raw).try_into().expect("invalid size from Emacs");
53-
env.handle_exit(result)
59+
Ok(self.len)
60+
}
61+
62+
#[inline]
63+
pub fn len(&self) -> usize {
64+
self.len
65+
}
66+
67+
#[inline]
68+
pub fn value(&self) -> Value<'e> {
69+
self.value
5470
}
5571
}
5672

5773
impl<'e> FromLisp<'e> for Vector<'e> {
5874
fn from_lisp(value: Value<'e>) -> Result<Vector<'e>> {
59-
let vector = Vector(value);
60-
// TODO: Confirm that this is indeed cheaper than calling vectorp and signaling error.
61-
vector.size()?;
62-
Ok(vector)
75+
let env = value.env;
76+
let len = unsafe_raw_call!(env, vec_size, value.raw)?.try_into()
77+
.expect("Invalid size from Emacs");
78+
Ok(Vector { value, len })
6379
}
6480
}
6581

6682
impl<'e> IntoLisp<'e> for Vector<'e> {
6783
#[inline(always)]
6884
fn into_lisp(self, _: &'e Env) -> Result<Value<'_>> {
69-
Ok(self.0)
85+
Ok(self.value)
86+
}
87+
}
88+
89+
/// An iterator over the elements of a [`Vector`], as [`Value`] structs.
90+
///
91+
/// [`Vector`]: struct.Vector.html
92+
/// [`Value`]: struct.Value.html
93+
pub struct IntoIter<'e> {
94+
vector: Vector<'e>,
95+
i: usize,
96+
}
97+
98+
impl<'e> Iterator for IntoIter<'e> {
99+
type Item = Value<'e>;
100+
101+
fn next(&mut self) -> Option<Self::Item> {
102+
let i = self.i;
103+
if i >= self.vector.len {
104+
None
105+
} else {
106+
self.i += 1;
107+
Some(self.vector.get(i).unwrap_or_else(|err| panic!(err)))
108+
}
109+
}
110+
111+
fn size_hint(&self) -> (usize, Option<usize>) {
112+
let remaining = self.vector.len - self.i;
113+
(remaining, Some(remaining))
114+
}
115+
}
116+
117+
impl<'e> ExactSizeIterator for IntoIter<'e> {}
118+
119+
impl<'e> IntoIterator for Vector<'e> {
120+
type Item = Value<'e>;
121+
122+
type IntoIter = IntoIter<'e>;
123+
124+
#[inline]
125+
fn into_iter(self) -> Self::IntoIter {
126+
IntoIter { vector: self, i: 0 }
70127
}
71128
}
72129

73130
impl Env {
74131
pub fn make_vector<'e, T: IntoLisp<'e>>(&'e self, length: usize, init: T) -> Result<Vector> {
75-
self.call(subr::make_vector, (length, init)).map(Vector)
132+
let value = self.call(subr::make_vector, (length, init))?;
133+
Ok(Vector::from_value_unchecked(value, length))
76134
}
77135

78136
pub fn vector<'e, A: IntoLispArgs<'e>>(&'e self, args: A) -> Result<Vector> {
79-
self.call(subr::vector, args).map(Vector)
137+
self.call(subr::vector, args).and_then(|v| v.into_rust())
80138
}
81139
}

test-module/src/call.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ fn value<'e>(function: Value<'e>, arg: Value) -> Result<Value<'e>> {
4343

4444
#[defun]
4545
fn mapc_vec(function: Value, vector: emacs::Vector) -> Result<()> {
46-
for i in 0..vector.size()? as usize {
47-
let elem: Value = vector.get(i)?;
46+
for (i, elem) in vector.into_iter().enumerate() {
4847
function.call((i, elem))?;
4948
}
5049
Ok(())

test-module/src/test_vector.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
use emacs::{defun, Result, Value, Vector};
44

55
#[defun(mod_in_name = false)]
6-
fn vec_size(v: Vector) -> Result<i64> {
7-
v.size().map(|s| s as i64)
6+
fn vec_size(v: Vector) -> Result<usize> {
7+
Ok(v.len())
88
}
99

1010
#[defun(mod_in_name = false)]
@@ -24,7 +24,7 @@ fn identity_if_vector(v: Vector) -> Result<Vector> {
2424

2525
#[defun(mod_in_name = false)]
2626
fn stringify_num_vector(v: Vector) -> Result<Vector> {
27-
for i in 0..v.size()? {
27+
for i in 0..v.len() {
2828
let x: i64 = v.get(i)?;
2929
v.set(i, format!("{}", x))?;
3030
}

0 commit comments

Comments
 (0)