|
1 | 1 | extern crate unicode_categories; |
2 | 2 | extern crate unicode_xid; |
3 | 3 |
|
| 4 | +use std::cell::Cell; |
4 | 5 | use std::char; |
5 | 6 | use std::fmt; |
6 | 7 | use std::ops::Range; |
@@ -28,6 +29,7 @@ use crate::vm::VirtualMachine; |
28 | 29 | use super::objbytes::PyBytes; |
29 | 30 | use super::objdict::PyDict; |
30 | 31 | use super::objint::{self, PyInt}; |
| 32 | +use super::objiter; |
31 | 33 | use super::objnone::PyNone; |
32 | 34 | use super::objsequence::PySliceableSequence; |
33 | 35 | use super::objslice::PySlice; |
@@ -90,6 +92,79 @@ impl TryIntoRef<PyString> for &str { |
90 | 92 | } |
91 | 93 | } |
92 | 94 |
|
| 95 | +#[pyclass] |
| 96 | +#[derive(Debug)] |
| 97 | +pub struct PyStringIterator { |
| 98 | + pub string: PyStringRef, |
| 99 | + position: Cell<usize>, |
| 100 | +} |
| 101 | + |
| 102 | +impl PyValue for PyStringIterator { |
| 103 | + fn class(vm: &VirtualMachine) -> PyClassRef { |
| 104 | + vm.ctx.striterator_type() |
| 105 | + } |
| 106 | +} |
| 107 | + |
| 108 | +#[pyimpl] |
| 109 | +impl PyStringIterator { |
| 110 | + #[pymethod(name = "__next__")] |
| 111 | + fn next(&self, vm: &VirtualMachine) -> PyResult { |
| 112 | + let pos = self.position.get(); |
| 113 | + |
| 114 | + if pos < self.string.value.chars().count() { |
| 115 | + self.position.set(self.position.get() + 1); |
| 116 | + |
| 117 | + #[allow(clippy::range_plus_one)] |
| 118 | + let value = self.string.value.do_slice(pos..pos + 1); |
| 119 | + |
| 120 | + value.into_pyobject(vm) |
| 121 | + } else { |
| 122 | + Err(objiter::new_stop_iteration(vm)) |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + #[pymethod(name = "__iter__")] |
| 127 | + fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> { |
| 128 | + zelf |
| 129 | + } |
| 130 | +} |
| 131 | + |
| 132 | +#[pyclass] |
| 133 | +#[derive(Debug)] |
| 134 | +pub struct PyStringReverseIterator { |
| 135 | + pub position: Cell<usize>, |
| 136 | + pub string: PyStringRef, |
| 137 | +} |
| 138 | + |
| 139 | +impl PyValue for PyStringReverseIterator { |
| 140 | + fn class(vm: &VirtualMachine) -> PyClassRef { |
| 141 | + vm.ctx.strreverseiterator_type() |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +#[pyimpl] |
| 146 | +impl PyStringReverseIterator { |
| 147 | + #[pymethod(name = "__next__")] |
| 148 | + fn next(&self, vm: &VirtualMachine) -> PyResult { |
| 149 | + if self.position.get() > 0 { |
| 150 | + let position: usize = self.position.get() - 1; |
| 151 | + |
| 152 | + #[allow(clippy::range_plus_one)] |
| 153 | + let value = self.string.value.do_slice(position..position + 1); |
| 154 | + |
| 155 | + self.position.set(position); |
| 156 | + value.into_pyobject(vm) |
| 157 | + } else { |
| 158 | + Err(objiter::new_stop_iteration(vm)) |
| 159 | + } |
| 160 | + } |
| 161 | + |
| 162 | + #[pymethod(name = "__iter__")] |
| 163 | + fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> { |
| 164 | + zelf |
| 165 | + } |
| 166 | +} |
| 167 | + |
93 | 168 | #[pyimpl] |
94 | 169 | impl PyString { |
95 | 170 | // TODO: should with following format |
@@ -1025,6 +1100,24 @@ impl PyString { |
1025 | 1100 | let encoded = PyBytes::from_string(&self.value, &encoding, vm)?; |
1026 | 1101 | Ok(encoded.into_pyobject(vm)?) |
1027 | 1102 | } |
| 1103 | + |
| 1104 | + #[pymethod(name = "__iter__")] |
| 1105 | + fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyStringIterator { |
| 1106 | + PyStringIterator { |
| 1107 | + position: Cell::new(0), |
| 1108 | + string: zelf, |
| 1109 | + } |
| 1110 | + } |
| 1111 | + |
| 1112 | + #[pymethod(name = "__reversed__")] |
| 1113 | + fn reversed(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyStringReverseIterator { |
| 1114 | + let begin = zelf.value.chars().count(); |
| 1115 | + |
| 1116 | + PyStringReverseIterator { |
| 1117 | + position: Cell::new(begin), |
| 1118 | + string: zelf, |
| 1119 | + } |
| 1120 | + } |
1028 | 1121 | } |
1029 | 1122 |
|
1030 | 1123 | impl PyValue for PyString { |
@@ -1053,6 +1146,9 @@ impl IntoPyObject for &String { |
1053 | 1146 |
|
1054 | 1147 | pub fn init(ctx: &PyContext) { |
1055 | 1148 | PyString::extend_class(ctx, &ctx.str_type); |
| 1149 | + |
| 1150 | + PyStringIterator::extend_class(ctx, &ctx.striterator_type); |
| 1151 | + PyStringReverseIterator::extend_class(ctx, &ctx.strreverseiterator_type); |
1056 | 1152 | } |
1057 | 1153 |
|
1058 | 1154 | pub fn get_value(obj: &PyObjectRef) -> String { |
|
0 commit comments