rune/modules/cmp.rs
1//! Comparison and ordering.
2
3use core::cmp::Ordering;
4
5use crate as rune;
6use crate::alloc;
7use crate::alloc::fmt::TryWrite;
8use crate::runtime::{Formatter, Protocol, Value};
9use crate::shared::Caller;
10use crate::{docstring, hash_in};
11use crate::{ContextError, Hash, Module, VmError};
12
13/// Comparison and ordering.
14#[rune::module(::std::cmp)]
15pub fn module() -> Result<Module, ContextError> {
16 let mut m = Module::from_meta(self::module__meta)?;
17
18 {
19 let ty = m.ty::<Ordering>()?.docs(docstring! {
20 /// An `Ordering` is the result of a comparison between two values.
21 ///
22 /// # Examples
23 ///
24 /// ```rune
25 /// use std::cmp::Ordering;
26 /// use std::ops::cmp;
27 ///
28 /// let result = 1.cmp(2);
29 /// assert_eq!(Ordering::Less, result);
30 ///
31 /// let result = 1.cmp(1);
32 /// assert_eq!(Ordering::Equal, result);
33 ///
34 /// let result = 2.cmp(1);
35 /// assert_eq!(Ordering::Greater, result);
36 /// ```
37 })?;
38
39 let mut ty = ty.make_enum(&["Less", "Equal", "Greater"])?;
40
41 ty.variant_mut(0)?
42 .make_empty()?
43 .constructor(|| Ordering::Less)?
44 .docs(docstring! {
45 /// "An ordering where a compared value is less than another.
46 })?;
47
48 ty.variant_mut(1)?
49 .make_empty()?
50 .constructor(|| Ordering::Equal)?
51 .docs(docstring! {
52 /// "An ordering where a compared value is equal to another.
53 })?;
54
55 ty.variant_mut(2)?
56 .make_empty()?
57 .constructor(|| Ordering::Greater)?
58 .docs(docstring! {
59 /// "An ordering where a compared value is greater than another.
60 })?;
61
62 m.function_meta(ordering_is_variant__meta)?;
63 }
64
65 m.function_meta(ordering_partial_eq__meta)?;
66 m.implement_trait::<Ordering>(rune::item!(::std::cmp::PartialEq))?;
67
68 m.function_meta(ordering_eq__meta)?;
69 m.implement_trait::<Ordering>(rune::item!(::std::cmp::Eq))?;
70
71 m.function_meta(ordering_debug_fmt)?;
72 m.function_meta(min__meta)?;
73 m.function_meta(max__meta)?;
74
75 let mut t = m.define_trait(["PartialEq"])?;
76
77 t.docs(docstring! {
78 /// Trait for comparisons using the equality operator.
79 ///
80 /// Implementing this trait for types provides the `==` and `!=`
81 /// operators for those types.
82 ///
83 /// `x.eq(y)` can also be written `x == y`, and `x.ne(y)` can be written
84 /// `x != y`. We use the easier-to-read infix notation in the remainder
85 /// of this documentation.
86 ///
87 /// This trait allows for comparisons using the equality operator, for
88 /// types that do not have a full equivalence relation. For example, in
89 /// floating point numbers `NaN != NaN`, so floating point types
90 /// implement `PartialEq` but not [`trait@Eq`]. Formally speaking, when
91 /// `Rhs == Self`, this trait corresponds to a [partial equivalence
92 /// relation].
93 ///
94 /// [partial equivalence relation]:
95 /// https://en.wikipedia.org/wiki/Partial_equivalence_relation
96 ///
97 /// Implementations must ensure that `eq` and `ne` are consistent with
98 /// each other:
99 ///
100 /// - `a != b` if and only if `!(a == b)`.
101 ///
102 /// The default implementation of `ne` provides this consistency and is
103 /// almost always sufficient. It should not be overridden without very
104 /// good reason.
105 ///
106 /// If [`PartialOrd`] or [`Ord`] are also implemented for `Self` and
107 /// `Rhs`, their methods must also be consistent with `PartialEq` (see
108 /// the documentation of those traits for the exact requirements). It's
109 /// easy to accidentally make them disagree by deriving some of the
110 /// traits and manually implementing others.
111 ///
112 /// The equality relation `==` must satisfy the following conditions
113 /// (for all `a`, `b`, `c` of type `A`, `B`, `C`):
114 ///
115 /// - **Symmetry**: if `A: PartialEq<B>` and `B: PartialEq<A>`, then
116 /// **`a == b` implies `b == a`**; and
117 ///
118 /// - **Transitivity**: if `A: PartialEq<B>` and `B: PartialEq<C>` and
119 /// `A: PartialEq<C>`, then **`a == b` and `b == c` implies `a ==
120 /// c`**. This must also work for longer chains, such as when `A:
121 /// PartialEq<B>`, `B: PartialEq<C>`, `C: PartialEq<D>`, and `A:
122 /// PartialEq<D>` all exist.
123 ///
124 /// Note that the `B: PartialEq<A>` (symmetric) and `A: PartialEq<C>`
125 /// (transitive) impls are not forced to exist, but these requirements
126 /// apply whenever they do exist.
127 ///
128 /// Violating these requirements is a logic error. The behavior
129 /// resulting from a logic error is not specified, but users of the
130 /// trait must ensure that such logic errors do *not* result in
131 /// undefined behavior. This means that `unsafe` code **must not** rely
132 /// on the correctness of these methods.
133 ///
134 /// ## Cross-crate considerations
135 ///
136 /// Upholding the requirements stated above can become tricky when one
137 /// crate implements `PartialEq` for a type of another crate (i.e., to
138 /// allow comparing one of its own types with a type from the standard
139 /// library). The recommendation is to never implement this trait for a
140 /// foreign type. In other words, such a crate should do `impl
141 /// PartialEq<ForeignType> for LocalType`, but it should *not* do `impl
142 /// PartialEq<LocalType> for ForeignType`.
143 ///
144 /// This avoids the problem of transitive chains that criss-cross crate
145 /// boundaries: for all local types `T`, you may assume that no other
146 /// crate will add `impl`s that allow comparing `T == U`. In other
147 /// words, if other crates add `impl`s that allow building longer
148 /// transitive chains `U1 == ... == T == V1 == ...`, then all the types
149 /// that appear to the right of `T` must be types that the crate
150 /// defining `T` already knows about. This rules out transitive chains
151 /// where downstream crates can add new `impl`s that "stitch together"
152 /// comparisons of foreign types in ways that violate transitivity.
153 ///
154 /// Not having such foreign `impl`s also avoids forward compatibility
155 /// issues where one crate adding more `PartialEq` implementations can
156 /// cause build failures in downstream crates.
157 ///
158 /// # Examples
159 ///
160 /// ```rune
161 /// let x = 0;
162 /// let y = 1;
163 ///
164 /// assert_eq!(x == y, false);
165 /// assert_eq!(x.eq(y), false);
166 ///
167 /// assert!((1.0).eq(1.0));
168 /// assert!(!(1.0).eq(2.0));
169 ///
170 /// assert!(1.0 == 1.0);
171 /// assert!(1.0 != 2.0);
172 /// ```
173 })?;
174
175 t.handler(|cx| {
176 let partial_eq = cx.find(&Protocol::PARTIAL_EQ)?;
177 let partial_eq = Caller::<(Value, Value), 2, bool>::new(partial_eq);
178
179 cx.function("ne", move |a: Value, b: Value| -> Result<bool, VmError> {
180 Ok(!partial_eq.call((a, b))?)
181 })?;
182
183 Ok(())
184 })?;
185
186 t.function("eq")?
187 .argument_types::<(Value, Value)>()?
188 .return_type::<bool>()?
189 .docs(docstring! {
190 /// Compare two values for equality.
191 ///
192 /// # Examples
193 ///
194 /// ```rune
195 /// assert_eq!(1.eq(2), false);
196 /// assert_eq!(2.eq(2), true);
197 /// assert_eq!(2.eq(1), false);
198 /// ```
199 })?;
200
201 t.function("ne")?
202 .argument_types::<(Value, Value)>()?
203 .return_type::<bool>()?
204 .docs(docstring! {
205 /// Compare two values for inequality.
206 ///
207 /// # Examples
208 ///
209 /// ```rune
210 /// assert_eq!(1.ne(2), true);
211 /// assert_eq!(2.ne(2), false);
212 /// assert_eq!(2.ne(1), true);
213 /// ```
214 })?;
215
216 let mut t = m.define_trait(["Eq"])?;
217
218 t.docs(docstring! {
219 /// Trait for comparisons corresponding to [equivalence relations](
220 /// https://en.wikipedia.org/wiki/Equivalence_relation).
221 ///
222 /// This means, that in addition to `a == b` and `a != b` being strict
223 /// inverses, the relation must be (for all `a`, `b` and `c`):
224 ///
225 /// - reflexive: `a == a`;
226 /// - symmetric: `a == b` implies `b == a` (required by `PartialEq` as
227 /// well); and
228 /// - transitive: `a == b` and `b == c` implies `a == c` (required by
229 /// `PartialEq` as well).
230 ///
231 /// This property cannot be checked by the compiler, and therefore `Eq`
232 /// implies [`PartialEq`], and has no extra methods.
233 ///
234 /// Violating this property is a logic error. The behavior resulting
235 /// from a logic error is not specified, but users of the trait must
236 /// ensure that such logic errors do *not* result in undefined behavior.
237 /// This means that `unsafe` code **must not** rely on the correctness
238 /// of these methods.
239 ///
240 /// Implement `Eq` in addition to `PartialEq` if it's guaranteed that
241 /// `PartialEq::eq(a, a)` always returns `true` (reflexivity), in
242 /// addition to the symmetric and transitive properties already required
243 /// by `PartialEq`.
244 /// ```
245 })?;
246
247 t.handler(|cx| {
248 _ = cx.find(&Protocol::EQ)?;
249 Ok(())
250 })?;
251
252 t.docs(docstring! {
253 /// Trait for equality comparisons.
254 ///
255 /// This trait allows for comparing whether two values are equal or not.
256 ///
257 /// # Examples
258 ///
259 /// ```rune
260 /// use std::cmp::Eq;
261 ///
262 /// assert!(1.eq(1));
263 /// assert!(!1.eq(2));
264 /// ```
265 })?;
266
267 let mut t = m.define_trait(["PartialOrd"])?;
268
269 t.docs(docstring! {
270 /// Trait for types that form a [partial
271 /// order](https://en.wikipedia.org/wiki/Partial_order).
272 ///
273 /// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called
274 /// using the `<`, `<=`, `>`, and `>=` operators, respectively.
275 ///
276 /// The methods of this trait must be consistent with each other and
277 /// with those of [`PartialEq`]. The following conditions must hold:
278 ///
279 /// 1. `a == b` if and only if `partial_cmp(a, b) == Some(Equal)`.
280 /// 2. `a < b` if and only if `partial_cmp(a, b) == Some(Less)`
281 /// 3. `a > b` if and only if `partial_cmp(a, b) == Some(Greater)`
282 /// 4. `a <= b` if and only if `a < b || a == b` 5. `a >= b` if and only
283 /// if `a > b || a == b`
284 /// 6. `a != b` if and only if `!(a == b)`.
285 ///
286 /// Conditions 2–5 above are ensured by the default implementation.
287 /// Condition 6 is already ensured by [`PartialEq`].
288 ///
289 /// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be
290 /// consistent with `partial_cmp` (see the documentation of that trait
291 /// for the exact requirements). It's easy to accidentally make them
292 /// disagree by deriving some of the traits and manually implementing
293 /// others.
294 ///
295 /// The comparison relations must satisfy the following conditions (for
296 /// all `a`, `b`, `c` of type `A`, `B`, `C`):
297 ///
298 /// - **Transitivity**: if `A: PartialOrd<B>` and `B: PartialOrd<C>` and
299 /// `A: PartialOrd<C>`, then `a < b` and `b < c` implies `a < c`. The
300 /// same must hold for both `==` and `>`. This must also work for
301 /// longer chains, such as when `A: PartialOrd<B>`, `B:
302 /// PartialOrd<C>`, `C: PartialOrd<D>`, and `A: PartialOrd<D>` all
303 /// exist.
304 /// - **Duality**: if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then `a
305 /// < b` if and only if `b > a`.
306 ///
307 /// Note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>`
308 /// (transitive) impls are not forced to exist, but these requirements
309 /// apply whenever they do exist.
310 ///
311 /// Violating these requirements is a logic error. The behavior
312 /// resulting from a logic error is not specified, but users of the
313 /// trait must ensure that such logic errors do *not* result in
314 /// undefined behavior. This means that `unsafe` code **must not** rely
315 /// on the correctness of these methods.
316 ///
317 /// ## Cross-crate considerations
318 ///
319 /// Upholding the requirements stated above can become tricky when one
320 /// crate implements `PartialOrd` for a type of another crate (i.e., to
321 /// allow comparing one of its own types with a type from the standard
322 /// library). The recommendation is to never implement this trait for a
323 /// foreign type. In other words, such a crate should do `impl
324 /// PartialOrd<ForeignType> for LocalType`, but it should *not* do `impl
325 /// PartialOrd<LocalType> for ForeignType`.
326 ///
327 /// This avoids the problem of transitive chains that criss-cross crate
328 /// boundaries: for all local types `T`, you may assume that no other
329 /// crate will add `impl`s that allow comparing `T < U`. In other words,
330 /// if other crates add `impl`s that allow building longer transitive
331 /// chains `U1 < ... < T < V1 < ...`, then all the types that appear to
332 /// the right of `T` must be types that the crate defining `T` already
333 /// knows about. This rules out transitive chains where downstream
334 /// crates can add new `impl`s that "stitch together" comparisons of
335 /// foreign types in ways that violate transitivity.
336 ///
337 /// Not having such foreign `impl`s also avoids forward compatibility
338 /// issues where one crate adding more `PartialOrd` implementations can
339 /// cause build failures in downstream crates.
340 ///
341 /// ## Corollaries
342 ///
343 /// The following corollaries follow from the above requirements:
344 ///
345 /// - irreflexivity of `<` and `>`: `!(a < a)`, `!(a > a)`
346 /// - transitivity of `>`: if `a > b` and `b > c` then `a > c`
347 /// - duality of `partial_cmp`: `partial_cmp(a, b) == partial_cmp(b,
348 /// a).map(Ordering::reverse)`
349 ///
350 /// ## Strict and non-strict partial orders
351 ///
352 /// The `<` and `>` operators behave according to a *strict* partial
353 /// order. However, `<=` and `>=` do **not** behave according to a
354 /// *non-strict* partial order. That is because mathematically, a
355 /// non-strict partial order would require reflexivity, i.e. `a <= a`
356 /// would need to be true for every `a`. This isn't always the case for
357 /// types that implement `PartialOrd`, for example:
358 ///
359 /// ```
360 /// let a = f64::sqrt(-1.0);
361 /// assert_eq!(a <= a, false);
362 /// ```
363 ///
364 /// ## How can I implement `PartialOrd`?
365 ///
366 /// `PartialOrd` only requires implementation of the [`PARTIAL_CMP`]
367 /// protocol, with the others generated from default implementations.
368 ///
369 /// However it remains possible to implement the others separately for
370 /// types which do not have a total order. For example, for floating
371 /// point numbers, `NaN < 0 == false` and `NaN >= 0 == false` (cf. IEEE
372 /// 754-2008 section 5.11).
373 ///
374 /// `PARTIAL_CMP` requires your type to be [`PARTIAL_EQ`].
375 ///
376 /// If your type is [`ORD`], you can implement [`PARTIAL_CMP`] by using
377 /// [`CMP`].
378 ///
379 /// You may also find it useful to use [`PARTIAL_CMP`] on your type's
380 /// fields.
381 ///
382 /// # Examples
383 ///
384 /// ```rune
385 /// let x = 0;
386 /// let y = 1;
387 ///
388 /// assert_eq!(x < y, true);
389 /// assert_eq!(x.lt(y), true);
390 /// ```
391 ///
392 /// [`partial_cmp`]: PartialOrd::partial_cmp
393 /// [`cmp`]: Ord::cmp
394 })?;
395
396 t.handler(|cx| {
397 let partial_cmp = cx.find(&Protocol::PARTIAL_CMP)?;
398 let partial_cmp = Caller::<(Value, Value), 2, Option<Ordering>>::new(partial_cmp);
399
400 cx.find_or_define(&Protocol::LT, {
401 let partial_cmp = partial_cmp.clone();
402
403 move |a: Value, b: Value| -> Result<bool, VmError> {
404 let Some(o) = partial_cmp.call((a.clone(), b.clone()))? else {
405 return Ok(false);
406 };
407
408 Ok(matches!(o, Ordering::Less))
409 }
410 })?;
411
412 cx.find_or_define(&Protocol::LE, {
413 let partial_cmp = partial_cmp.clone();
414
415 move |a: Value, b: Value| -> Result<bool, VmError> {
416 let Some(o) = partial_cmp.call((a.clone(), b.clone()))? else {
417 return Ok(false);
418 };
419
420 Ok(matches!(o, Ordering::Less | Ordering::Equal))
421 }
422 })?;
423
424 cx.find_or_define(&Protocol::GT, {
425 let partial_cmp = partial_cmp.clone();
426
427 move |a: Value, b: Value| -> Result<bool, VmError> {
428 let Some(o) = partial_cmp.call((a.clone(), b.clone()))? else {
429 return Ok(false);
430 };
431
432 Ok(matches!(o, Ordering::Greater))
433 }
434 })?;
435
436 cx.find_or_define(&Protocol::GE, {
437 let partial_cmp = partial_cmp.clone();
438
439 move |a: Value, b: Value| -> Result<bool, VmError> {
440 let Some(o) = partial_cmp.call((a.clone(), b.clone()))? else {
441 return Ok(false);
442 };
443
444 Ok(matches!(o, Ordering::Greater | Ordering::Equal))
445 }
446 })?;
447
448 Ok(())
449 })?;
450
451 t.function("partial_cmp")?
452 .argument_types::<(Value, Value)>()?
453 .return_type::<Option<Ordering>>()?
454 .docs(docstring! {
455 /// Compare two values.
456 ///
457 /// # Examples
458 ///
459 /// ```rune
460 /// use std::cmp::Ordering;
461 ///
462 /// assert_eq!(1.partial_cmp(2), Some(Ordering::Less));
463 /// assert_eq!(2.partial_cmp(2), Some(Ordering::Equal));
464 /// assert_eq!(2.partial_cmp(1), Some(Ordering::Greater));
465 /// ```
466 })?;
467
468 t.function("lt")?
469 .argument_types::<(Value, Value)>()?
470 .return_type::<bool>()?
471 .docs(docstring! {
472 /// Tests less than (for `self` and `other`) and is used by the `<` operator.
473 ///
474 /// # Examples
475 ///
476 /// ```rune
477 /// assert_eq!(1.0 < 1.0, false);
478 /// assert_eq!(1.0 < 2.0, true);
479 /// assert_eq!(2.0 < 1.0, false);
480 /// ```
481 })?;
482
483 t.function("le")?
484 .argument_types::<(Value, Value)>()?
485 .return_type::<bool>()?
486 .docs(docstring! {
487 /// Tests less than or equal to (for `self` and `other`) and is used
488 /// by the `<=` operator.
489 ///
490 /// # Examples
491 ///
492 /// ```rune
493 /// assert_eq!(1.0 <= 1.0, true);
494 /// assert_eq!(1.0 <= 2.0, true);
495 /// assert_eq!(2.0 <= 1.0, false);
496 /// ```
497 })?;
498
499 t.function("gt")?
500 .argument_types::<(Value, Value)>()?
501 .return_type::<bool>()?
502 .docs(docstring! {
503 /// Tests greater than (for `self` and `other`) and is used by the
504 /// `>` operator.
505 ///
506 /// # Examples
507 ///
508 /// ```rune
509 /// assert_eq!(1.0 > 1.0, false);
510 /// assert_eq!(1.0 > 2.0, false);
511 /// assert_eq!(2.0 > 1.0, true);
512 /// ```
513 })?;
514
515 t.function("ge")?
516 .argument_types::<(Value, Value)>()?
517 .return_type::<bool>()?
518 .docs(docstring! {
519 /// Tests greater than or equal to (for `self` and `other`) and is
520 /// used by the `>=` operator.
521 ///
522 /// # Examples
523 ///
524 /// ```rune
525 /// assert_eq!(1.0 >= 1.0, true);
526 /// assert_eq!(1.0 >= 2.0, false);
527 /// assert_eq!(2.0 >= 1.0, true);
528 /// ```
529 })?;
530
531 let mut t = m.define_trait(["Ord"])?;
532
533 t.docs(docstring! {
534 /// Trait for types that form a [total
535 /// order](https://en.wikipedia.org/wiki/Total_order).
536 ///
537 /// Implementations must be consistent with the [`PartialOrd`]
538 /// implementation, and ensure `max`, `min`, and `clamp` are consistent
539 /// with `cmp`:
540 ///
541 /// - `partial_cmp(a, b) == Some(cmp(a, b))`.
542 /// - `max(a, b) == max_by(a, b, cmp)` (ensured by the default
543 /// implementation).
544 /// - `min(a, b) == min_by(a, b, cmp)` (ensured by the default
545 /// implementation).
546 /// - For `a.clamp(min, max)`, see the [method docs](#method.clamp)
547 /// (ensured by the default implementation).
548 ///
549 /// It's easy to accidentally make `cmp` and `partial_cmp` disagree by
550 /// deriving some of the traits and manually implementing others.
551 ///
552 /// Violating these requirements is a logic error. The behavior
553 /// resulting from a logic error is not specified, but users of the
554 /// trait must ensure that such logic errors do *not* result in
555 /// undefined behavior. This means that `unsafe` code **must not** rely
556 /// on the correctness of these methods.
557 ///
558 /// ## Corollaries
559 ///
560 /// From the above and the requirements of `PartialOrd`, it follows that
561 /// for all `a`, `b` and `c`:
562 ///
563 /// - exactly one of `a < b`, `a == b` or `a > b` is true; and
564 /// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same
565 /// must hold for both `==` and `>`.
566 ///
567 /// Mathematically speaking, the `<` operator defines a strict [weak
568 /// order]. In cases where `==` conforms to mathematical equality, it
569 /// also defines a strict [total order].
570 ///
571 /// [weak order]: https://en.wikipedia.org/wiki/Weak_ordering
572 /// [total order]: https://en.wikipedia.org/wiki/Total_order
573 ///
574 /// ## Lexicographical comparison
575 ///
576 /// Lexicographical comparison is an operation with the following
577 /// properties:
578 /// - Two sequences are compared element by element.
579 /// - The first mismatching element defines which sequence is
580 /// lexicographically less or greater than the other.
581 /// - If one sequence is a prefix of another, the shorter sequence is
582 /// lexicographically less than the other.
583 /// - If two sequences have equivalent elements and are of the same
584 /// length, then the sequences are lexicographically equal.
585 /// - An empty sequence is lexicographically less than any non-empty
586 /// sequence.
587 /// - Two empty sequences are lexicographically equal.
588 ///
589 /// ## How can I implement `Ord`?
590 ///
591 /// `Ord` requires that the type also be [`PARTIAL_RD`] and [`EQ`]
592 /// (which requires [`PARTIAL_EQ`]).
593 ///
594 /// Then you must define an implementation for [`CMP`]. You may find it
595 /// useful to use [`CMP`] on your type's fields.
596 })?;
597
598 t.handler(|cx| {
599 let cmp = cx.find(&Protocol::CMP)?;
600 let cmp = Caller::<(Value, Value), 2, Ordering>::new(cmp);
601
602 cx.find_or_define(&Protocol::MIN, {
603 let cmp = cmp.clone();
604
605 move |a: Value, b: Value| -> Result<_, VmError> {
606 match cmp.call((a.clone(), b.clone()))? {
607 Ordering::Less | Ordering::Equal => Ok(a),
608 Ordering::Greater => Ok(b),
609 }
610 }
611 })?;
612
613 cx.find_or_define(&Protocol::MAX, {
614 let cmp = cmp.clone();
615
616 move |a: Value, b: Value| -> Result<_, VmError> {
617 match cmp.call((a.clone(), b.clone()))? {
618 Ordering::Less | Ordering::Equal => Ok(b),
619 Ordering::Greater => Ok(a),
620 }
621 }
622 })?;
623
624 Ok(())
625 })?;
626
627 t.function("cmp")?
628 .argument_types::<(Value, Value)>()?
629 .return_type::<Ordering>()?
630 .docs(docstring! {
631 /// Compare two values.
632 ///
633 /// # Examples
634 ///
635 /// ```rune
636 /// use std::cmp::Ordering;
637 ///
638 /// assert_eq!(1.cmp(2), Ordering::Less);
639 /// assert_eq!(2.cmp(2), Ordering::Equal);
640 /// assert_eq!(2.cmp(1), Ordering::Greater);
641 /// ```
642 })?;
643
644 t.function("min")?
645 .argument_types::<(Value, Value)>()?
646 .return_type::<Ordering>()?
647 .docs(docstring! {
648 /// Return the minimum of two values.
649 ///
650 /// # Examples
651 ///
652 /// ```rune
653 /// assert_eq!(1.min(2), 1);
654 /// assert_eq!(2.min(2), 2);
655 /// assert_eq!(2.min(1), 1);
656 /// ```
657 })?;
658
659 t.function("max")?
660 .argument_types::<(Value, Value)>()?
661 .return_type::<Ordering>()?
662 .docs(docstring! {
663 /// Return the maximum of two values.
664 ///
665 /// # Examples
666 ///
667 /// ```rune
668 /// assert_eq!(1.max(2), 2);
669 /// assert_eq!(2.max(2), 2);
670 /// assert_eq!(2.max(1), 2);
671 /// ```
672 })?;
673
674 Ok(m)
675}
676
677#[rune::function(keep, instance, protocol = IS_VARIANT)]
678#[inline]
679pub(crate) fn ordering_is_variant(this: Ordering, hash: Hash) -> bool {
680 match (this, hash) {
681 (Ordering::Less, hash_in!(crate, ::std::cmp::Ordering::Less)) => true,
682 (Ordering::Equal, hash_in!(crate, ::std::cmp::Ordering::Equal)) => true,
683 (Ordering::Greater, hash_in!(crate, ::std::cmp::Ordering::Greater)) => true,
684 _ => false,
685 }
686}
687
688/// Compares and returns the maximum of two values.
689///
690/// Returns the second argument if the comparison determines them to be equal.
691///
692/// Internally uses the [`CMP`] protocol.
693///
694/// # Examples
695///
696/// ```rune
697/// use std::cmp::max;
698///
699/// assert_eq!(max(1, 2), 2);
700/// assert_eq!(max(2, 2), 2);
701/// ```
702#[rune::function(keep)]
703fn max(v1: Value, v2: Value) -> Result<Value, VmError> {
704 Ok(match Value::cmp(&v1, &v2)? {
705 Ordering::Less | Ordering::Equal => v2,
706 Ordering::Greater => v1,
707 })
708}
709
710/// Compares and returns the minimum of two values.
711///
712/// Returns the first argument if the comparison determines them to be equal.
713///
714/// Internally uses the [`CMP`] protocol.
715///
716/// # Examples
717///
718/// ```rune
719/// use std::cmp::min;
720///
721/// assert_eq!(min(1, 2), 1);
722/// assert_eq!(min(2, 2), 2);
723/// ```
724#[rune::function(keep)]
725fn min(v1: Value, v2: Value) -> Result<Value, VmError> {
726 Ok(match Value::cmp(&v1, &v2)? {
727 Ordering::Less | Ordering::Equal => v1,
728 Ordering::Greater => v2,
729 })
730}
731
732/// Perform a partial ordering equality test.
733///
734/// # Examples
735///
736/// ```rune
737/// use std::cmp::Ordering;
738///
739/// assert!(Ordering::Less == Ordering::Less);
740/// assert!(Ordering::Less != Ordering::Equal);
741/// ```
742#[rune::function(keep, instance, protocol = PARTIAL_EQ)]
743fn ordering_partial_eq(this: Ordering, other: Ordering) -> bool {
744 this == other
745}
746
747/// Perform a total ordering equality test.
748///
749/// # Examples
750///
751/// ```rune
752/// use std::ops::eq;
753/// use std::cmp::Ordering;
754///
755/// assert!(eq(Ordering::Less, Ordering::Less));
756/// assert!(!eq(Ordering::Less, Ordering::Equal));
757/// ```
758#[rune::function(keep, instance, protocol = EQ)]
759fn ordering_eq(this: Ordering, other: Ordering) -> bool {
760 this == other
761}
762
763/// Debug format [`Ordering`].
764///
765/// # Examples
766///
767/// ```rune
768/// use std::cmp::Ordering;
769///
770/// assert_eq!(format!("{:?}", Ordering::Less), "Less");
771/// ```
772#[rune::function(instance, protocol = DEBUG_FMT)]
773fn ordering_debug_fmt(this: Ordering, s: &mut Formatter) -> alloc::Result<()> {
774 write!(s, "{this:?}")
775}