rune/modules/
ops.rs

1//! Overloadable operators and associated types.
2
3pub mod generator;
4
5use core::cmp::Ordering;
6
7use once_cell::sync::OnceCell;
8use rune::item;
9
10use crate as rune;
11use crate::alloc::hash_map::RandomState;
12use crate::runtime::range::RangeIter;
13use crate::runtime::range_from::RangeFromIter;
14use crate::runtime::range_inclusive::RangeInclusiveIter;
15use crate::runtime::{
16    ControlFlow, EnvProtocolCaller, Function, Hasher, Range, RangeFrom, RangeFull, RangeInclusive,
17    RangeTo, RangeToInclusive, Value, VmResult,
18};
19use crate::{ContextError, Module};
20
21static STATE: OnceCell<RandomState> = OnceCell::new();
22
23/// Overloadable operators and associated types.
24#[rune::module(::std::ops)]
25pub fn module() -> Result<Module, ContextError> {
26    let mut m = Module::from_meta(self::module_meta)?;
27
28    macro_rules! iter {
29        ($ty:ident) => {
30            m.ty::<$ty<i64>>()?;
31            m.function_meta($ty::<i64>::next__meta)?;
32            m.function_meta($ty::<i64>::size_hint__meta)?;
33            m.implement_trait::<$ty<i64>>(rune::item!(::std::iter::Iterator))?;
34
35            m.ty::<$ty<u64>>()?;
36            m.function_meta($ty::<u64>::next__meta)?;
37            m.function_meta($ty::<u64>::size_hint__meta)?;
38            m.implement_trait::<$ty<u64>>(rune::item!(::std::iter::Iterator))?;
39
40            m.ty::<$ty<char>>()?;
41            m.function_meta($ty::<char>::next__meta)?;
42            m.function_meta($ty::<char>::size_hint__meta)?;
43            m.implement_trait::<$ty<char>>(rune::item!(::std::iter::Iterator))?;
44        };
45    }
46
47    macro_rules! double_ended {
48        ($ty:ident) => {
49            iter!($ty);
50
51            m.function_meta($ty::<i64>::next_back__meta)?;
52            m.implement_trait::<$ty<i64>>(rune::item!(::std::iter::DoubleEndedIterator))?;
53
54            m.function_meta($ty::<i64>::len__meta)?;
55            m.implement_trait::<$ty<i64>>(rune::item!(::std::iter::ExactSizeIterator))?;
56
57            m.function_meta($ty::<u64>::next_back__meta)?;
58            m.implement_trait::<$ty<u64>>(rune::item!(::std::iter::DoubleEndedIterator))?;
59
60            m.function_meta($ty::<u64>::len__meta)?;
61            m.implement_trait::<$ty<u64>>(rune::item!(::std::iter::ExactSizeIterator))?;
62
63            m.function_meta($ty::<char>::next_back__meta)?;
64            m.implement_trait::<$ty<char>>(rune::item!(::std::iter::DoubleEndedIterator))?;
65        };
66    }
67
68    {
69        m.ty::<RangeFrom>()?;
70        m.function_meta(RangeFrom::iter__meta)?;
71        m.function_meta(RangeFrom::into_iter__meta)?;
72        m.function_meta(RangeFrom::contains__meta)?;
73
74        m.function_meta(RangeFrom::partial_eq__meta)?;
75        m.implement_trait::<RangeFrom>(item!(::std::cmp::PartialEq))?;
76
77        m.function_meta(RangeFrom::eq__meta)?;
78        m.implement_trait::<RangeFrom>(item!(::std::cmp::Eq))?;
79
80        m.function_meta(RangeFrom::partial_cmp__meta)?;
81        m.implement_trait::<RangeFrom>(item!(::std::cmp::PartialOrd))?;
82
83        m.function_meta(RangeFrom::cmp__meta)?;
84        m.implement_trait::<RangeFrom>(item!(::std::cmp::Ord))?;
85
86        iter!(RangeFromIter);
87    }
88
89    {
90        m.ty::<RangeFull>()?;
91        m.function_meta(RangeFull::contains__meta)?;
92
93        m.function_meta(RangeFull::partial_eq__meta)?;
94        m.implement_trait::<RangeFull>(item!(::std::cmp::PartialEq))?;
95
96        m.function_meta(RangeFull::eq__meta)?;
97        m.implement_trait::<RangeFull>(item!(::std::cmp::Eq))?;
98
99        m.function_meta(RangeFull::partial_cmp__meta)?;
100        m.implement_trait::<RangeFull>(item!(::std::cmp::PartialOrd))?;
101
102        m.function_meta(RangeFull::cmp__meta)?;
103        m.implement_trait::<RangeFull>(item!(::std::cmp::Ord))?;
104    }
105
106    {
107        m.ty::<RangeInclusive>()?;
108        m.function_meta(RangeInclusive::iter__meta)?;
109        m.function_meta(RangeInclusive::into_iter__meta)?;
110        m.function_meta(RangeInclusive::contains__meta)?;
111
112        m.function_meta(RangeInclusive::partial_eq__meta)?;
113        m.implement_trait::<RangeInclusive>(item!(::std::cmp::PartialEq))?;
114
115        m.function_meta(RangeInclusive::eq__meta)?;
116        m.implement_trait::<RangeInclusive>(item!(::std::cmp::Eq))?;
117
118        m.function_meta(RangeInclusive::partial_cmp__meta)?;
119        m.implement_trait::<RangeInclusive>(item!(::std::cmp::PartialOrd))?;
120
121        m.function_meta(RangeInclusive::cmp__meta)?;
122        m.implement_trait::<RangeInclusive>(item!(::std::cmp::Ord))?;
123
124        double_ended!(RangeInclusiveIter);
125    }
126
127    {
128        m.ty::<RangeToInclusive>()?;
129        m.function_meta(RangeToInclusive::contains__meta)?;
130
131        m.function_meta(RangeToInclusive::partial_eq__meta)?;
132        m.implement_trait::<RangeToInclusive>(item!(::std::cmp::PartialEq))?;
133
134        m.function_meta(RangeToInclusive::eq__meta)?;
135        m.implement_trait::<RangeToInclusive>(item!(::std::cmp::Eq))?;
136
137        m.function_meta(RangeToInclusive::partial_cmp__meta)?;
138        m.implement_trait::<RangeToInclusive>(item!(::std::cmp::PartialOrd))?;
139
140        m.function_meta(RangeToInclusive::cmp__meta)?;
141        m.implement_trait::<RangeToInclusive>(item!(::std::cmp::Ord))?;
142    }
143
144    {
145        m.ty::<RangeTo>()?;
146        m.function_meta(RangeTo::contains__meta)?;
147
148        m.function_meta(RangeTo::partial_eq__meta)?;
149        m.implement_trait::<RangeTo>(item!(::std::cmp::PartialEq))?;
150
151        m.function_meta(RangeTo::eq__meta)?;
152        m.implement_trait::<RangeTo>(item!(::std::cmp::Eq))?;
153
154        m.function_meta(RangeTo::partial_cmp__meta)?;
155        m.implement_trait::<RangeTo>(item!(::std::cmp::PartialOrd))?;
156
157        m.function_meta(RangeTo::cmp__meta)?;
158        m.implement_trait::<RangeTo>(item!(::std::cmp::Ord))?;
159    }
160
161    {
162        m.ty::<Range>()?;
163        m.function_meta(Range::iter__meta)?;
164        m.function_meta(Range::into_iter__meta)?;
165        m.function_meta(Range::contains__meta)?;
166
167        m.function_meta(Range::partial_eq__meta)?;
168        m.implement_trait::<Range>(item!(::std::cmp::PartialEq))?;
169
170        m.function_meta(Range::eq__meta)?;
171        m.implement_trait::<Range>(item!(::std::cmp::Eq))?;
172
173        m.function_meta(Range::partial_cmp__meta)?;
174        m.implement_trait::<Range>(item!(::std::cmp::PartialOrd))?;
175
176        m.function_meta(Range::cmp__meta)?;
177        m.implement_trait::<Range>(item!(::std::cmp::Ord))?;
178
179        double_ended!(RangeIter);
180    }
181
182    {
183        m.ty::<ControlFlow>()?;
184
185        m.function_meta(ControlFlow::partial_eq__meta)?;
186        m.implement_trait::<ControlFlow>(item!(::std::cmp::PartialEq))?;
187
188        m.function_meta(ControlFlow::eq__meta)?;
189        m.implement_trait::<ControlFlow>(item!(::std::cmp::Eq))?;
190
191        m.function_meta(ControlFlow::debug_fmt__meta)?;
192
193        m.function_meta(ControlFlow::clone__meta)?;
194        m.implement_trait::<ControlFlow>(item!(::std::clone::Clone))?;
195    }
196
197    m.ty::<Function>()?;
198    m.function_meta(Function::clone__meta)?;
199    m.implement_trait::<Function>(item!(::std::clone::Clone))?;
200    m.function_meta(Function::debug_fmt__meta)?;
201
202    m.function_meta(partial_eq__meta)?;
203    m.function_meta(eq__meta)?;
204    m.function_meta(partial_cmp__meta)?;
205    m.function_meta(cmp__meta)?;
206    m.function_meta(hash__meta)?;
207
208    m.reexport(["Generator"], item!(::std::ops::generator::Generator))?;
209    m.reexport(
210        ["GeneratorState"],
211        item!(::std::ops::generator::GeneratorState),
212    )?;
213    Ok(m)
214}
215
216/// Perform a partial equality check over two values.
217///
218/// This produces the same behavior as the equality operator (`==`).
219///
220/// For non-builtin types this leans on the behavior of the [`PARTIAL_EQ`]
221/// protocol.
222///
223/// # Panics
224///
225/// Panics if we're trying to compare two values which are not comparable.
226///
227/// # Examples
228///
229/// ```rune
230/// use std::ops::partial_eq;
231///
232/// assert!(partial_eq(1.0, 1.0));
233/// assert!(!partial_eq(1.0, 2.0));
234/// ```
235#[rune::function(keep)]
236fn partial_eq(lhs: Value, rhs: Value) -> VmResult<bool> {
237    Value::partial_eq(&lhs, &rhs)
238}
239
240/// Perform a partial equality check over two values.
241///
242/// This produces the same behavior as the equality operator (`==`).
243///
244/// For non-builtin types this leans on the behavior of the [`EQ`] protocol.
245///
246/// # Panics
247///
248/// Panics if we're trying to compare two values which are not comparable.
249///
250/// # Examples
251///
252/// ```rune
253/// use std::ops::eq;
254///
255/// assert!(eq(1.0, 1.0));
256/// assert!(!eq(1.0, 2.0));
257/// ```
258#[rune::function(keep)]
259fn eq(lhs: Value, rhs: Value) -> VmResult<bool> {
260    Value::eq(&lhs, &rhs)
261}
262
263/// Perform a partial comparison over two values.
264///
265/// This produces the same behavior as when comparison operators like less than
266/// (`<`) is used.
267///
268/// For non-builtin types this leans on the behavior of the [`PARTIAL_CMP`]
269/// protocol.
270///
271/// # Panics
272///
273/// Panics if we're trying to compare two values which are not comparable.
274///
275/// # Examples
276///
277/// ```rune
278/// use std::ops::partial_cmp;
279/// use std::cmp::Ordering;
280///
281/// assert_eq!(partial_cmp(1.0, 1.0), Some(Ordering::Equal));
282/// assert_eq!(partial_cmp(1.0, 2.0), Some(Ordering::Less));
283/// assert_eq!(partial_cmp(1.0, f64::NAN), None);
284/// ```
285#[rune::function(keep)]
286fn partial_cmp(lhs: Value, rhs: Value) -> VmResult<Option<Ordering>> {
287    Value::partial_cmp(&lhs, &rhs)
288}
289
290/// Perform a total comparison over two values.
291///
292/// For non-builtin types this leans on the behavior of the [`CMP`] protocol.
293///
294/// # Panics
295///
296/// Panics if we're trying to compare two values which are not comparable.
297///
298/// ```rune,should_panic
299/// use std::ops::cmp;
300///
301/// let _ = cmp(1.0, f64::NAN);
302/// ```
303///
304/// # Examples
305///
306/// ```rune
307/// use std::ops::cmp;
308/// use std::cmp::Ordering;
309///
310/// assert_eq!(cmp(1, 1), Ordering::Equal);
311/// assert_eq!(cmp(1, 2), Ordering::Less);
312/// ```
313#[rune::function(keep)]
314fn cmp(lhs: Value, rhs: Value) -> VmResult<Ordering> {
315    Value::cmp(&lhs, &rhs)
316}
317
318/// Hashes the given function.
319///
320/// For non-builtin types this uses the [`HASH`] protocol.
321///
322/// # Hash stability
323///
324/// The hash is guaranteed to be stable within a single virtual machine
325/// invocation, but not across virtual machines. So returning the hash from one
326/// and calculating it in another using an identical value is not guaranteed to
327/// produce the same hash.
328///
329/// # Panics
330///
331/// Panics if we try to generate a hash from an unhashable value.
332///
333/// # Examples
334///
335/// ```rune
336/// use std::ops::hash;
337///
338/// assert_eq!(hash([1, 2]), hash((1, 2)));
339/// ```
340#[rune::function(keep)]
341fn hash(value: Value) -> VmResult<u64> {
342    let state = STATE.get_or_init(RandomState::new);
343    let mut hasher = Hasher::new_with(state);
344
345    vm_try!(Value::hash_with(
346        &value,
347        &mut hasher,
348        &mut EnvProtocolCaller
349    ));
350
351    VmResult::Ok(hasher.finish())
352}