rune/runtime/
range.rs

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/// Type for a range expression `start..end`.
16///
17/// # Examples
18///
19/// ```rune
20/// let range = 0..10;
21/// assert!(!range.contains(-10));
22/// assert!(range.contains(5));
23/// assert!(!range.contains(10));
24/// assert!(!range.contains(20));
25///
26/// assert!(range is std::ops::Range);
27/// ```
28///
29/// Ranges can contain any type:
30///
31/// ```rune
32/// let range = 'a'..'f';
33/// assert_eq!(range.start, 'a');
34/// range.start = 'b';
35/// assert_eq!(range.start, 'b');
36/// assert_eq!(range.end, 'f');
37/// range.end = 'g';
38/// assert_eq!(range.end, 'g');
39/// ```
40///
41/// Certain ranges can be used as iterators:
42///
43/// ```rune
44/// let range = 'a'..'e';
45/// assert_eq!(range.iter().collect::<Vec>(), ['a', 'b', 'c', 'd']);
46/// ```
47///
48/// # Examples
49///
50/// ```rust
51/// use rune::runtime::Range;
52///
53/// let start = rune::to_value(1)?;
54/// let end = rune::to_value(10)?;
55/// let _ = Range::new(start, end);
56/// # Ok::<_, rune::support::Error>(())
57/// ```
58#[derive(Any, Clone, TryClone)]
59#[try_clone(crate)]
60#[rune(crate, constructor, item = ::std::ops)]
61pub struct Range {
62    /// The start value of the range.
63    #[rune(get, set)]
64    pub start: Value,
65    /// The to value of the range.
66    #[rune(get, set)]
67    pub end: Value,
68}
69
70impl Range {
71    /// Construct a new range.
72    pub fn new(start: Value, end: Value) -> Self {
73        Self { start, end }
74    }
75
76    /// Iterate over the range.
77    ///
78    /// # Panics
79    ///
80    /// This panics if the range is not a well-defined range.
81    ///
82    /// # Examples
83    ///
84    /// ```rune
85    /// let range = 'a'..'e';
86    /// assert_eq!(range.iter().collect::<Vec>(), ['a', 'b', 'c', 'd']);
87    /// ```
88    ///
89    /// Cannot construct an iterator over floats:
90    ///
91    /// ```rune,should_panic
92    /// let range = 1.0..2.0;
93    /// range.iter()
94    /// ```
95    #[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    /// Iterate over the range.
121    ///
122    /// # Panics
123    ///
124    /// This panics if the range is not a well-defined range.
125    ///
126    /// # Examples
127    ///
128    /// ```rune
129    /// let vec = [];
130    ///
131    /// for value in 'a'..'e' {
132    ///     vec.push(value);
133    /// }
134    ///
135    /// assert_eq!(vec, ['a', 'b', 'c', 'd']);
136    /// ```
137    ///
138    /// Cannot construct an iterator over floats:
139    ///
140    /// ```rune,should_panic
141    /// for value in 1.0..2.0 {
142    /// }
143    /// ```
144    #[rune::function(keep, protocol = INTO_ITER)]
145    pub fn into_iter(&self) -> VmResult<Value> {
146        self.iter()
147    }
148
149    /// Test the range for partial equality.
150    ///
151    /// # Examples
152    ///
153    /// ```rune
154    /// let range = 'a'..'e';
155    /// assert!(range == ('a'..'e'));
156    /// assert!(range != ('b'..'e'));
157    ///
158    /// let range = 1.0..2.0;
159    /// assert!(range == (1.0..2.0));
160    /// assert!(range != (f64::NAN..2.0));
161    /// assert!((f64::NAN..2.0) != (f64::NAN..2.0));
162    /// ```
163    #[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    /// Test the range for total equality.
181    ///
182    /// # Examples
183    ///
184    /// ```rune
185    /// use std::ops::eq;
186    ///
187    /// let range = 'a'..'e';
188    /// assert!(eq(range, 'a'..'e'));
189    /// assert!(!eq(range, 'b'..'e'));
190    /// ```
191    #[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    /// Test the range for partial ordering.
205    ///
206    /// # Examples
207    ///
208    /// ```rune
209    /// assert!(('a'..'e') < ('b'..'e'));
210    /// assert!(('c'..'e') > ('b'..'e'));
211    /// assert!(!((f64::NAN..2.0) > (f64::INFINITY..2.0)));
212    /// assert!(!((f64::NAN..2.0) < (f64::INFINITY..2.0)));
213    /// ```
214    #[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    /// Test the range for total ordering.
233    ///
234    /// # Examples
235    ///
236    /// ```rune
237    /// use std::ops::cmp;
238    /// use std::cmp::Ordering;
239    ///
240    /// assert_eq!(cmp('a'..'e', 'b'..'e'), Ordering::Less);
241    /// assert_eq!(cmp('c'..'e', 'b'..'e'), Ordering::Greater);
242    /// ```
243    #[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    /// Test if the range contains the given value.
258    ///
259    /// The check is performed using the [`PARTIAL_CMP`] protocol.
260    ///
261    /// # Examples
262    ///
263    /// ```rune
264    /// let range = 0..10;
265    ///
266    /// assert!(!range.contains(-10));
267    /// assert!(range.contains(5));
268    /// assert!(!range.contains(10));
269    /// assert!(!range.contains(20));
270    ///
271    /// assert!(range is std::ops::Range);
272    /// ```
273    #[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});