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