rune/runtime/
range_inclusive.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 an inclusive range expression `start..=end`.
15///
16/// # Examples
17///
18/// ```rune
19/// let range = 0..=10;
20///
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::RangeInclusive);
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', 'e']);
46/// ```
47///
48/// # Rust Examples
49///
50/// ```rust
51/// use rune::runtime::RangeInclusive;
52///
53/// let start = rune::to_value(1)?;
54/// let end = rune::to_value(10)?;
55/// let _ = RangeInclusive::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 RangeInclusive {
62    /// The start value of the range.
63    #[rune(get, set)]
64    pub start: Value,
65    /// The end value of the range.
66    #[rune(get, set)]
67    pub end: Value,
68}
69
70impl RangeInclusive {
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', 'e']);
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) -> Result<Value, VmError> {
97        let value = match (self.start.as_ref(), self.end.as_ref()) {
98            (Repr::Inline(Inline::Unsigned(start)), Repr::Inline(end)) => {
99                let end = end.as_integer::<u64>()?;
100                rune::to_value(RangeInclusiveIter::new(*start..=end))?
101            }
102            (Repr::Inline(Inline::Signed(start)), Repr::Inline(end)) => {
103                let end = end.as_integer::<i64>()?;
104                rune::to_value(RangeInclusiveIter::new(*start..=end))?
105            }
106            (Repr::Inline(Inline::Char(start)), Repr::Inline(Inline::Char(end))) => {
107                rune::to_value(RangeInclusiveIter::new(*start..=*end))?
108            }
109            (start, end) => {
110                return Err(VmError::new(VmErrorKind::UnsupportedIterRangeInclusive {
111                    start: start.type_info(),
112                    end: end.type_info(),
113                }))
114            }
115        };
116
117        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', 'e']);
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) -> Result<Value, VmError> {
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) -> Result<bool, VmError> {
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    ) -> Result<bool, VmError> {
173        if !Value::partial_eq_with(&self.start, &b.start, caller)? {
174            return 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) -> Result<bool, VmError> {
193        self.eq_with(other, &mut EnvProtocolCaller)
194    }
195
196    pub(crate) fn eq_with(
197        &self,
198        b: &Self,
199        caller: &mut dyn ProtocolCaller,
200    ) -> Result<bool, VmError> {
201        if !Value::eq_with(&self.start, &b.start, caller)? {
202            return Ok(false);
203        }
204
205        Value::eq_with(&self.end, &b.end, caller)
206    }
207
208    /// Test the range for partial ordering.
209    ///
210    /// # Examples
211    ///
212    /// ```rune
213    /// assert!(('a'..='e') < ('b'..='e'));
214    /// assert!(('c'..='e') > ('b'..='e'));
215    /// assert!(!((f64::NAN..=2.0) > (f64::INFINITY..=2.0)));
216    /// assert!(!((f64::NAN..=2.0) < (f64::INFINITY..=2.0)));
217    /// ```
218    #[rune::function(keep, protocol = PARTIAL_CMP)]
219    pub fn partial_cmp(&self, other: &Self) -> Result<Option<Ordering>, VmError> {
220        self.partial_cmp_with(other, &mut EnvProtocolCaller)
221    }
222
223    pub(crate) fn partial_cmp_with(
224        &self,
225        b: &Self,
226        caller: &mut dyn ProtocolCaller,
227    ) -> Result<Option<Ordering>, VmError> {
228        match Value::partial_cmp_with(&self.start, &b.start, caller)? {
229            Some(Ordering::Equal) => (),
230            other => return Ok(other),
231        }
232
233        Value::partial_cmp_with(&self.end, &b.end, caller)
234    }
235
236    /// Test the range for total ordering.
237    ///
238    /// # Examples
239    ///
240    /// ```rune
241    /// use std::ops::cmp;
242    /// use std::cmp::Ordering;
243    ///
244    /// assert_eq!(cmp('a'..='e', 'b'..='e'), Ordering::Less);
245    /// assert_eq!(cmp('c'..='e', 'b'..='e'), Ordering::Greater);
246    /// ```
247    #[rune::function(keep, protocol = CMP)]
248    pub fn cmp(&self, other: &Self) -> Result<Ordering, VmError> {
249        self.cmp_with(other, &mut EnvProtocolCaller)
250    }
251
252    pub(crate) fn cmp_with(
253        &self,
254        b: &Self,
255        caller: &mut dyn ProtocolCaller,
256    ) -> Result<Ordering, VmError> {
257        match Value::cmp_with(&self.start, &b.start, caller)? {
258            Ordering::Equal => (),
259            other => return Ok(other),
260        }
261
262        Value::cmp_with(&self.end, &b.end, caller)
263    }
264
265    /// Test if the range contains the given value.
266    ///
267    /// The check is performed using the [`PARTIAL_CMP`] protocol.
268    ///
269    /// # Examples
270    ///
271    /// ```rune
272    /// let range = 0..=10;
273    ///
274    /// assert!(!range.contains(-10));
275    /// assert!(range.contains(5));
276    /// assert!(range.contains(10));
277    /// assert!(!range.contains(20));
278    ///
279    /// assert!(range is std::ops::RangeInclusive);
280    /// ```
281    #[rune::function(keep)]
282    pub(crate) fn contains(&self, value: Value) -> Result<bool, VmError> {
283        self.contains_with(value, &mut EnvProtocolCaller)
284    }
285
286    pub(crate) fn contains_with(
287        &self,
288        value: Value,
289        caller: &mut dyn ProtocolCaller,
290    ) -> Result<bool, VmError> {
291        match Value::partial_cmp_with(&self.start, &value, caller)? {
292            Some(Ordering::Less | Ordering::Equal) => {}
293            _ => return Ok(false),
294        }
295
296        Ok(matches!(
297            Value::partial_cmp_with(&self.end, &value, caller)?,
298            Some(Ordering::Greater | Ordering::Equal)
299        ))
300    }
301}
302
303impl fmt::Debug for RangeInclusive {
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        write!(f, "{:?}..={:?}", self.start, self.end)
306    }
307}
308
309impl<Idx> ToValue for ops::RangeInclusive<Idx>
310where
311    Idx: ToValue,
312{
313    fn to_value(self) -> Result<Value, RuntimeError> {
314        let (start, end) = self.into_inner();
315        let start = start.to_value()?;
316        let end = end.to_value()?;
317        Ok(Value::new(RangeInclusive::new(start, end))?)
318    }
319}
320
321impl<Idx> FromValue for ops::RangeInclusive<Idx>
322where
323    Idx: FromValue,
324{
325    #[inline]
326    fn from_value(value: Value) -> Result<Self, RuntimeError> {
327        let range = value.downcast::<RangeInclusive>()?;
328        let start = Idx::from_value(range.start)?;
329        let end = Idx::from_value(range.end)?;
330        Ok(start..=end)
331    }
332}
333
334double_ended_range_iter!(RangeInclusive, RangeInclusiveIter<T>, {
335    #[rune::function(instance, keep, protocol = SIZE_HINT)]
336    #[inline]
337    pub(crate) fn size_hint(&self) -> (usize, Option<usize>) {
338        self.iter.size_hint()
339    }
340
341    #[rune::function(instance, keep, protocol = LEN)]
342    #[inline]
343    pub(crate) fn len(&self) -> Result<usize, VmError>
344    where
345        T: Copy + StepsBetween + fmt::Debug,
346    {
347        let Some(result) = T::steps_between(*self.iter.start(), *self.iter.end()) else {
348            return Err(VmError::panic(format!(
349                "could not calculate length of range {:?}..={:?}",
350                self.iter.start(),
351                self.iter.end()
352            )));
353        };
354
355        Ok(result)
356    }
357});