1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use derive_more::Display;
use gazebo::{any::AnyLifetime, coerce::Coerce};
use crate as starlark;
use crate::values::{Heap, StarlarkValue, Value, ValueLike};
#[derive(Debug, Trace, Coerce, Display, Freeze, NoSerialize, AnyLifetime)]
#[display(fmt = "iterator")]
#[repr(C)]
struct StringIteratorGen<V> {
string: V,
produce_char: bool,
}
pub(crate) fn iterate_chars<'v>(string: Value<'v>, heap: &'v Heap) -> Value<'v> {
heap.alloc(StringIterator {
string,
produce_char: true,
})
}
pub(crate) fn iterate_codepoints<'v>(string: Value<'v>, heap: &'v Heap) -> Value<'v> {
heap.alloc(StringIterator {
string,
produce_char: false,
})
}
starlark_complex_value!(StringIterator);
impl<'v, T: ValueLike<'v>> StarlarkValue<'v> for StringIteratorGen<T>
where
Self: AnyLifetime<'v>,
{
starlark_type!("iterator");
fn iterate<'a>(
&'a self,
heap: &'v Heap,
) -> anyhow::Result<Box<dyn Iterator<Item = Value<'v>> + 'a>>
where
'v: 'a,
{
let s = self.string.to_value().unpack_str().unwrap().chars();
if self.produce_char {
Ok(box s.map(move |x| heap.alloc(x)))
} else {
Ok(box s.map(|x| Value::new_int(u32::from(x) as i32)))
}
}
fn with_iterator(
&self,
heap: &'v Heap,
f: &mut dyn FnMut(&mut dyn Iterator<Item = Value<'v>>) -> anyhow::Result<()>,
) -> anyhow::Result<()> {
let s = self.string.to_value().unpack_str().unwrap().chars();
if self.produce_char {
f(&mut s.map(|x| heap.alloc(x)))
} else {
f(&mut s.map(|x| Value::new_int(u32::from(x) as i32)))
}
}
}