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::Any;
8
9use super::{
10    EnvProtocolCaller, FromValue, Inline, ProtocolCaller, Repr, RuntimeError, StepsBetween,
11    ToValue, Value, VmError, VmErrorKind,
12};
13
14/// Type for a range expression `start..end`.
15///
16/// # Examples
17///
18/// ```rune
19/// let range = 0..10;
20/// assert!(!range.contains(-10));
21/// assert!(range.contains(5));
22/// assert!(!range.contains(10));
23/// assert!(!range.contains(20));
24///
25/// assert!(range is std::ops::Range);
26/// ```
27///
28/// Ranges can contain any type:
29///
30/// ```rune
31/// let range = 'a'..'f';
32/// assert_eq!(range.start, 'a');
33/// range.start = 'b';
34/// assert_eq!(range.start, 'b');
35/// assert_eq!(range.end, 'f');
36/// range.end = 'g';
37/// assert_eq!(range.end, 'g');
38/// ```
39///
40/// Certain ranges can be used as iterators:
41///
42/// ```rune
43/// let range = 'a'..'e';
44/// assert_eq!(range.iter().collect::<Vec>(), ['a', 'b', 'c', 'd']);
45/// ```
46///
47/// # Examples
48///
49/// ```rust
50/// use rune::runtime::Range;
51///
52/// let start = rune::to_value(1)?;
53/// let end = rune::to_value(10)?;
54/// let _ = Range::new(start, end);
55/// # Ok::<_, rune::support::Error>(())
56/// ```
57#[derive(Any, Clone, TryClone)]
58#[try_clone(crate)]
59#[rune(crate, constructor, item = ::std::ops)]
60pub struct Range {
61    /// The start value of the range.
62    #[rune(get, set)]
63    pub start: Value,
64    /// The to value of the range.
65    #[rune(get, set)]
66    pub end: Value,
67}
68
69impl Range {
70    /// Construct a new range.
71    pub fn new(start: Value, end: Value) -> Self {
72        Self { start, end }
73    }
74
75    /// Iterate over the range.
76    ///
77    /// # Panics
78    ///
79    /// This panics if the range is not a well-defined range.
80    ///
81    /// # Examples
82    ///
83    /// ```rune
84    /// let range = 'a'..'e';
85    /// assert_eq!(range.iter().collect::<Vec>(), ['a', 'b', 'c', 'd']);
86    /// ```
87    ///
88    /// Cannot construct an iterator over floats:
89    ///
90    /// ```rune,should_panic
91    /// let range = 1.0..2.0;
92    /// range.iter()
93    /// ```
94    #[rune::function(keep)]
95    pub fn iter(&self) -> Result<Value, VmError> {
96        let value = match (self.start.as_ref(), self.end.as_ref()) {
97            (Repr::Inline(Inline::Unsigned(start)), Repr::Inline(end)) => {
98                let end = end.as_integer::<u64>()?;
99                rune::to_value(RangeIter::new(*start..end))?
100            }
101            (Repr::Inline(Inline::Signed(start)), Repr::Inline(end)) => {
102                let end = end.as_integer::<i64>()?;
103                rune::to_value(RangeIter::new(*start..end))?
104            }
105            (Repr::Inline(Inline::Char(start)), Repr::Inline(Inline::Char(end))) => {
106                rune::to_value(RangeIter::new(*start..*end))?
107            }
108            (start, end) => {
109                return Err(VmError::from(VmErrorKind::UnsupportedIterRange {
110                    start: start.type_info(),
111                    end: end.type_info(),
112                }))
113            }
114        };
115
116        Ok(value)
117    }
118
119    /// Iterate over the range.
120    ///
121    /// # Panics
122    ///
123    /// This panics if the range is not a well-defined range.
124    ///
125    /// # Examples
126    ///
127    /// ```rune
128    /// let vec = [];
129    ///
130    /// for value in 'a'..'e' {
131    ///     vec.push(value);
132    /// }
133    ///
134    /// assert_eq!(vec, ['a', 'b', 'c', 'd']);
135    /// ```
136    ///
137    /// Cannot construct an iterator over floats:
138    ///
139    /// ```rune,should_panic
140    /// for value in 1.0..2.0 {
141    /// }
142    /// ```
143    #[rune::function(keep, protocol = INTO_ITER)]
144    pub fn into_iter(&self) -> Result<Value, VmError> {
145        self.iter()
146    }
147
148    /// Test the range for partial equality.
149    ///
150    /// # Examples
151    ///
152    /// ```rune
153    /// let range = 'a'..'e';
154    /// assert!(range == ('a'..'e'));
155    /// assert!(range != ('b'..'e'));
156    ///
157    /// let range = 1.0..2.0;
158    /// assert!(range == (1.0..2.0));
159    /// assert!(range != (f64::NAN..2.0));
160    /// assert!((f64::NAN..2.0) != (f64::NAN..2.0));
161    /// ```
162    #[rune::function(keep, protocol = PARTIAL_EQ)]
163    pub fn partial_eq(&self, other: &Self) -> Result<bool, VmError> {
164        self.partial_eq_with(other, &mut EnvProtocolCaller)
165    }
166
167    pub(crate) fn partial_eq_with(
168        &self,
169        b: &Self,
170        caller: &mut dyn ProtocolCaller,
171    ) -> Result<bool, VmError> {
172        if !Value::partial_eq_with(&self.start, &b.start, caller)? {
173            return Ok(false);
174        }
175
176        Value::partial_eq_with(&self.end, &b.end, caller)
177    }
178
179    /// Test the range for total equality.
180    ///
181    /// # Examples
182    ///
183    /// ```rune
184    /// use std::ops::eq;
185    ///
186    /// let range = 'a'..'e';
187    /// assert!(eq(range, 'a'..'e'));
188    /// assert!(!eq(range, 'b'..'e'));
189    /// ```
190    #[rune::function(keep, protocol = EQ)]
191    pub fn eq(&self, other: &Self) -> Result<bool, VmError> {
192        self.eq_with(other, &mut EnvProtocolCaller)
193    }
194
195    pub(crate) fn eq_with(
196        &self,
197        b: &Self,
198        caller: &mut dyn ProtocolCaller,
199    ) -> Result<bool, VmError> {
200        if !Value::eq_with(&self.start, &b.start, caller)? {
201            return Ok(false);
202        }
203
204        Value::eq_with(&self.end, &b.end, caller)
205    }
206
207    /// Test the range for partial ordering.
208    ///
209    /// # Examples
210    ///
211    /// ```rune
212    /// assert!(('a'..'e') < ('b'..'e'));
213    /// assert!(('c'..'e') > ('b'..'e'));
214    /// assert!(!((f64::NAN..2.0) > (f64::INFINITY..2.0)));
215    /// assert!(!((f64::NAN..2.0) < (f64::INFINITY..2.0)));
216    /// ```
217    #[rune::function(keep, protocol = PARTIAL_CMP)]
218    pub fn partial_cmp(&self, other: &Self) -> Result<Option<Ordering>, VmError> {
219        self.partial_cmp_with(other, &mut EnvProtocolCaller)
220    }
221
222    pub(crate) fn partial_cmp_with(
223        &self,
224        b: &Self,
225        caller: &mut dyn ProtocolCaller,
226    ) -> Result<Option<Ordering>, VmError> {
227        match Value::partial_cmp_with(&self.start, &b.start, caller)? {
228            Some(Ordering::Equal) => (),
229            other => return Ok(other),
230        }
231
232        Value::partial_cmp_with(&self.end, &b.end, caller)
233    }
234
235    /// Test the range for total ordering.
236    ///
237    /// # Examples
238    ///
239    /// ```rune
240    /// use std::ops::cmp;
241    /// use std::cmp::Ordering;
242    ///
243    /// assert_eq!(cmp('a'..'e', 'b'..'e'), Ordering::Less);
244    /// assert_eq!(cmp('c'..'e', 'b'..'e'), Ordering::Greater);
245    /// ```
246    #[rune::function(keep, protocol = CMP)]
247    pub fn cmp(&self, other: &Self) -> Result<Ordering, VmError> {
248        self.cmp_with(other, &mut EnvProtocolCaller)
249    }
250
251    pub(crate) fn cmp_with(
252        &self,
253        b: &Self,
254        caller: &mut dyn ProtocolCaller,
255    ) -> Result<Ordering, VmError> {
256        match Value::cmp_with(&self.start, &b.start, caller)? {
257            Ordering::Equal => (),
258            other => return Ok(other),
259        }
260
261        Value::cmp_with(&self.end, &b.end, caller)
262    }
263
264    /// Test if the range contains the given value.
265    ///
266    /// The check is performed using the [`PARTIAL_CMP`] protocol.
267    ///
268    /// # Examples
269    ///
270    /// ```rune
271    /// let range = 0..10;
272    ///
273    /// assert!(!range.contains(-10));
274    /// assert!(range.contains(5));
275    /// assert!(!range.contains(10));
276    /// assert!(!range.contains(20));
277    ///
278    /// assert!(range is std::ops::Range);
279    /// ```
280    #[rune::function(keep)]
281    pub(crate) fn contains(&self, value: Value) -> Result<bool, VmError> {
282        self.contains_with(value, &mut EnvProtocolCaller)
283    }
284
285    pub(crate) fn contains_with(
286        &self,
287        value: Value,
288        caller: &mut dyn ProtocolCaller,
289    ) -> Result<bool, VmError> {
290        match Value::partial_cmp_with(&self.start, &value, caller)? {
291            Some(Ordering::Less | Ordering::Equal) => {}
292            _ => return Ok(false),
293        }
294
295        Ok(matches!(
296            Value::partial_cmp_with(&self.end, &value, caller)?,
297            Some(Ordering::Greater)
298        ))
299    }
300}
301
302impl fmt::Debug for Range {
303    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304        write!(f, "{:?}..{:?}", self.start, self.end)
305    }
306}
307
308impl<Idx> ToValue for ops::Range<Idx>
309where
310    Idx: ToValue,
311{
312    fn to_value(self) -> Result<Value, RuntimeError> {
313        let start = self.start.to_value()?;
314        let end = self.end.to_value()?;
315        let range = Range::new(start, end);
316        Ok(Value::new(range)?)
317    }
318}
319
320impl<Idx> FromValue for ops::Range<Idx>
321where
322    Idx: FromValue,
323{
324    #[inline]
325    fn from_value(value: Value) -> Result<Self, RuntimeError> {
326        let range = value.downcast::<Range>()?;
327        let start = Idx::from_value(range.start)?;
328        let end = Idx::from_value(range.end)?;
329        Ok(ops::Range { start, end })
330    }
331}
332
333double_ended_range_iter!(Range, RangeIter<T>, {
334    #[rune::function(instance, keep, protocol = SIZE_HINT)]
335    #[inline]
336    pub(crate) fn size_hint(&self) -> (usize, Option<usize>) {
337        self.iter.size_hint()
338    }
339
340    #[rune::function(instance, keep, protocol = LEN)]
341    #[inline]
342    pub(crate) fn len(&self) -> Result<usize, VmError>
343    where
344        T: Copy + StepsBetween + fmt::Debug,
345    {
346        let Some(result) = T::steps_between(self.iter.start, self.iter.end) else {
347            return Err(VmError::panic(format!(
348                "could not calculate length of range {:?}..={:?}",
349                self.iter.start, self.iter.end
350            )));
351        };
352
353        Ok(result)
354    }
355});