1use core::cmp::Ordering;
2use core::fmt;
3use core::ops;
4
5use crate as rune;
6use crate::alloc::clone::TryClone;
7use crate::runtime::{
8 EnvProtocolCaller, FromValue, Inline, ProtocolCaller, Repr, RuntimeError, ToValue, Value,
9 VmErrorKind, VmResult,
10};
11use crate::Any;
12
13use super::StepsBetween;
14
15#[derive(Any, Clone, TryClone)]
59#[try_clone(crate)]
60#[rune(crate, constructor, item = ::std::ops)]
61pub struct Range {
62 #[rune(get, set)]
64 pub start: Value,
65 #[rune(get, set)]
67 pub end: Value,
68}
69
70impl Range {
71 pub fn new(start: Value, end: Value) -> Self {
73 Self { start, end }
74 }
75
76 #[rune::function(keep)]
96 pub fn iter(&self) -> VmResult<Value> {
97 let value = match (self.start.as_ref(), self.end.as_ref()) {
98 (Repr::Inline(Inline::Unsigned(start)), Repr::Inline(end)) => {
99 let end = vm_try!(end.as_integer::<u64>());
100 vm_try!(rune::to_value(RangeIter::new(*start..end)))
101 }
102 (Repr::Inline(Inline::Signed(start)), Repr::Inline(end)) => {
103 let end = vm_try!(end.as_integer::<i64>());
104 vm_try!(rune::to_value(RangeIter::new(*start..end)))
105 }
106 (Repr::Inline(Inline::Char(start)), Repr::Inline(Inline::Char(end))) => {
107 vm_try!(rune::to_value(RangeIter::new(*start..*end)))
108 }
109 (start, end) => {
110 return VmResult::err(VmErrorKind::UnsupportedIterRange {
111 start: start.type_info(),
112 end: end.type_info(),
113 })
114 }
115 };
116
117 VmResult::Ok(value)
118 }
119
120 #[rune::function(keep, protocol = INTO_ITER)]
145 pub fn into_iter(&self) -> VmResult<Value> {
146 self.iter()
147 }
148
149 #[rune::function(keep, protocol = PARTIAL_EQ)]
164 pub fn partial_eq(&self, other: &Self) -> VmResult<bool> {
165 self.partial_eq_with(other, &mut EnvProtocolCaller)
166 }
167
168 pub(crate) fn partial_eq_with(
169 &self,
170 b: &Self,
171 caller: &mut dyn ProtocolCaller,
172 ) -> VmResult<bool> {
173 if !vm_try!(Value::partial_eq_with(&self.start, &b.start, caller)) {
174 return VmResult::Ok(false);
175 }
176
177 Value::partial_eq_with(&self.end, &b.end, caller)
178 }
179
180 #[rune::function(keep, protocol = EQ)]
192 pub fn eq(&self, other: &Self) -> VmResult<bool> {
193 self.eq_with(other, &mut EnvProtocolCaller)
194 }
195
196 pub(crate) fn eq_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult<bool> {
197 if !vm_try!(Value::eq_with(&self.start, &b.start, caller)) {
198 return VmResult::Ok(false);
199 }
200
201 Value::eq_with(&self.end, &b.end, caller)
202 }
203
204 #[rune::function(keep, protocol = PARTIAL_CMP)]
215 pub fn partial_cmp(&self, other: &Self) -> VmResult<Option<Ordering>> {
216 self.partial_cmp_with(other, &mut EnvProtocolCaller)
217 }
218
219 pub(crate) fn partial_cmp_with(
220 &self,
221 b: &Self,
222 caller: &mut dyn ProtocolCaller,
223 ) -> VmResult<Option<Ordering>> {
224 match vm_try!(Value::partial_cmp_with(&self.start, &b.start, caller)) {
225 Some(Ordering::Equal) => (),
226 other => return VmResult::Ok(other),
227 }
228
229 Value::partial_cmp_with(&self.end, &b.end, caller)
230 }
231
232 #[rune::function(keep, protocol = CMP)]
244 pub fn cmp(&self, other: &Self) -> VmResult<Ordering> {
245 self.cmp_with(other, &mut EnvProtocolCaller)
246 }
247
248 pub(crate) fn cmp_with(&self, b: &Self, caller: &mut dyn ProtocolCaller) -> VmResult<Ordering> {
249 match vm_try!(Value::cmp_with(&self.start, &b.start, caller)) {
250 Ordering::Equal => (),
251 other => return VmResult::Ok(other),
252 }
253
254 Value::cmp_with(&self.end, &b.end, caller)
255 }
256
257 #[rune::function(keep)]
274 pub(crate) fn contains(&self, value: Value) -> VmResult<bool> {
275 self.contains_with(value, &mut EnvProtocolCaller)
276 }
277
278 pub(crate) fn contains_with(
279 &self,
280 value: Value,
281 caller: &mut dyn ProtocolCaller,
282 ) -> VmResult<bool> {
283 match vm_try!(Value::partial_cmp_with(&self.start, &value, caller)) {
284 Some(Ordering::Less | Ordering::Equal) => {}
285 _ => return VmResult::Ok(false),
286 }
287
288 VmResult::Ok(matches!(
289 vm_try!(Value::partial_cmp_with(&self.end, &value, caller)),
290 Some(Ordering::Greater)
291 ))
292 }
293}
294
295impl fmt::Debug for Range {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 write!(f, "{:?}..{:?}", self.start, self.end)
298 }
299}
300
301impl<Idx> ToValue for ops::Range<Idx>
302where
303 Idx: ToValue,
304{
305 fn to_value(self) -> Result<Value, RuntimeError> {
306 let start = self.start.to_value()?;
307 let end = self.end.to_value()?;
308 let range = Range::new(start, end);
309 Ok(Value::new(range)?)
310 }
311}
312
313impl<Idx> FromValue for ops::Range<Idx>
314where
315 Idx: FromValue,
316{
317 #[inline]
318 fn from_value(value: Value) -> Result<Self, RuntimeError> {
319 let range = value.downcast::<Range>()?;
320 let start = Idx::from_value(range.start)?;
321 let end = Idx::from_value(range.end)?;
322 Ok(ops::Range { start, end })
323 }
324}
325
326double_ended_range_iter!(Range, RangeIter<T>, {
327 #[rune::function(instance, keep, protocol = SIZE_HINT)]
328 #[inline]
329 pub(crate) fn size_hint(&self) -> (usize, Option<usize>) {
330 self.iter.size_hint()
331 }
332
333 #[rune::function(instance, keep, protocol = LEN)]
334 #[inline]
335 pub(crate) fn len(&self) -> VmResult<usize>
336 where
337 T: Copy + StepsBetween + fmt::Debug,
338 {
339 let Some(result) = T::steps_between(self.iter.start, self.iter.end) else {
340 return VmResult::panic(format!(
341 "could not calculate length of range {:?}..={:?}",
342 self.iter.start, self.iter.end
343 ));
344 };
345
346 VmResult::Ok(result)
347 }
348});