Skip to content

Commit

Permalink
Implement total ordering
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Aug 19, 2023
1 parent cbc81d3 commit b099125
Show file tree
Hide file tree
Showing 17 changed files with 411 additions and 98 deletions.
2 changes: 1 addition & 1 deletion crates/rune/src/diagnostics/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl VmError {
);

(
format!("type mismatch for operation `{}`", op),
format!("Type mismatch for operation `{}`", op),
vec![
format!("left hand side has type `{}`", lhs),
format!("right hand side has type `{}`", rhs),
Expand Down
6 changes: 3 additions & 3 deletions crates/rune/src/modules/collections/hash_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ impl HashSet {
/// ```rune
/// use std::collections::HashSet;
///
/// let mut v = HashSet::new();
/// let v = HashSet::new();
/// v.insert(1);
/// v.clear();
/// assert!(v.is_empty());
Expand All @@ -214,12 +214,12 @@ impl HashSet {
/// let a = HashSet::from([1, 2, 3]);
/// let b = HashSet::from([4, 2, 3, 4]);
///
/// let diff = a.difference(&b).collect::<HashSet>();
/// let diff = a.difference(b).collect::<HashSet>();
/// assert_eq!(diff, [1].iter().collect::<HashSet>());
///
/// // Note that difference is not symmetric,
/// // and `b - a` means something else:
/// let diff = b.difference(&a).collect::<HashSet>();
/// let diff = b.difference(a).collect::<HashSet>();
/// assert_eq!(diff, [4].iter().collect::<HashSet>());
/// ```
#[rune::function(instance, path = Self::difference)]
Expand Down
68 changes: 46 additions & 22 deletions crates/rune/src/modules/collections/vec_deque.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::cmp::Ordering;
use core::fmt::{self, Write};

use crate as rune;
Expand Down Expand Up @@ -54,7 +55,8 @@ pub(super) fn setup(m: &mut Module) -> Result<(), ContextError> {
m.associated_function(Protocol::INDEX_SET, VecDeque::set)?;
m.associated_function(Protocol::INTO_ITER, VecDeque::__rune_fn__iter)?;
m.associated_function(Protocol::STRING_DEBUG, VecDeque::string_debug)?;
m.associated_function(Protocol::EQ, eq)?;
m.associated_function(Protocol::EQ, VecDeque::eq)?;
m.associated_function(Protocol::CMP, VecDeque::cmp)?;
Ok(())
}

Expand Down Expand Up @@ -250,7 +252,7 @@ impl VecDeque {
/// ```rune
/// use std::collections::VecDeque;
///
/// let buf = [1].into::<VecDeque>();
/// let buf = VecDeque::from([1]);
/// buf.reserve(10);
/// assert!(buf.capacity() >= 11);
/// ```
Expand Down Expand Up @@ -504,6 +506,48 @@ impl VecDeque {
fn string_debug(&self, s: &mut String) -> fmt::Result {
write!(s, "{:?}", self.inner)
}

fn eq(this: &VecDeque, other: Value) -> VmResult<bool> {
let mut other = vm_try!(other.into_iter());

for a in &this.inner {
let Some(b) = vm_try!(other.next()) else {
return VmResult::Ok(false);
};

if !vm_try!(Value::eq(a, &b)) {
return VmResult::Ok(false);
}
}

if vm_try!(other.next()).is_some() {
return VmResult::Ok(false);
}

VmResult::Ok(true)
}

fn cmp(this: &VecDeque, other: &VecDeque) -> VmResult<Ordering> {
let mut a = this.inner.iter();
let mut b = other.inner.iter();

while let Some(a) = a.next() {
let Some(b) = b.next() else {
return VmResult::Ok(Ordering::Greater);
};

match vm_try!(Value::cmp(a, b)) {
Ordering::Equal => (),
other => return VmResult::Ok(other),
}
}

if b.next().is_some() {
return VmResult::Ok(Ordering::Less);
};

VmResult::Ok(Ordering::Equal)
}
}

/// Construct a [`VecDeque`] from a value.
Expand All @@ -519,23 +563,3 @@ impl VecDeque {
fn from(value: Value) -> VmResult<VecDeque> {
VecDeque::from_iter(vm_try!(value.into_iter()))
}

fn eq(this: &VecDeque, other: Value) -> VmResult<bool> {
let mut other = vm_try!(other.into_iter());

for a in &this.inner {
let Some(b) = vm_try!(other.next()) else {
return VmResult::Ok(false);
};

if !vm_try!(Value::eq(a, &b)) {
return VmResult::Ok(false);
}
}

if vm_try!(other.next()).is_some() {
return VmResult::Ok(false);
}

VmResult::Ok(true)
}
16 changes: 15 additions & 1 deletion crates/rune/src/modules/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,21 @@ use crate::{ContextError, Module};
pub fn module() -> Result<Module, ContextError> {
let mut m = Module::with_crate_item("std", ["vec"]);

m.ty::<Vec>()?;
m.ty::<Vec>()?.docs([
"A dynamic vector.",
"",
"This is the type that is constructed in rune when an array expression such as `[1, 2, 3]` is used.",
"",
"# Comparisons",
"",
"Shorter sequences are considered smaller than longer ones, and vice versa.",
"",
"```rune",
"assert!([1, 2, 3] < [1, 2, 3, 4]);",
"assert!([1, 2, 3] < [1, 2, 4]);",
"assert!([1, 2, 4] > [1, 2, 3]);",
"```",
]);

m.function_meta(vec_new)?;
m.function_meta(vec_with_capacity)?;
Expand Down
76 changes: 46 additions & 30 deletions crates/rune/src/runtime/object.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::borrow;
use core::cmp;
use core::cmp::Ordering;
use core::fmt;
use core::hash;
use core::iter;
Expand Down Expand Up @@ -293,9 +294,52 @@ impl Object {
Iterator::from("std::object::Iter", self.clone().into_iter())
}

/// Value pointer equals implementation for an Object.
pub(crate) fn eq_with(a: &Self, b: &Self, caller: &mut impl ProtocolCaller) -> VmResult<bool> {
map_ptr_eq(&a.inner, &b.inner, caller)
if a.inner.len() != b.inner.len() {
return VmResult::Ok(false);
}

for (key, a) in a.inner.iter() {
let Some(b) = b.inner.get(key) else {
return VmResult::Ok(false);
};

if !vm_try!(Value::eq_with(a, b, caller)) {
return VmResult::Ok(false);
}
}

VmResult::Ok(true)
}

pub(crate) fn cmp_with(
a: &Self,
b: &Self,
caller: &mut impl ProtocolCaller,
) -> VmResult<Ordering> {
let mut b = b.inner.iter();

for (k1, v1) in a.inner.iter() {
let Some((k2, v2)) = b.next() else {
return VmResult::Ok(Ordering::Greater);
};

match k1.cmp(k2) {
Ordering::Equal => (),
other => return VmResult::Ok(other),
}

match Value::cmp_with(v1, v2, caller) {
VmResult::Ok(Ordering::Equal) => (),
other => return other,
}
}

if b.next().is_some() {
return VmResult::Ok(Ordering::Less);
}

VmResult::Ok(Ordering::Equal)
}

/// Debug implementation for a struct. This assumes that all fields
Expand Down Expand Up @@ -373,31 +417,3 @@ impl fmt::Display for DebugStruct<'_> {
d.finish()
}
}

/// Helper function two compare two hashmaps of values.
pub(crate) fn map_ptr_eq<K>(
a: &BTreeMap<K, Value>,
b: &BTreeMap<K, Value>,
caller: &mut impl ProtocolCaller,
) -> VmResult<bool>
where
K: cmp::Eq + cmp::Ord,
K: hash::Hash,
{
if a.len() != b.len() {
return VmResult::Ok(false);
}

for (key, a) in a.iter() {
let b = match b.get(key) {
Some(b) => b,
None => return VmResult::Ok(false),
};

if !vm_try!(Value::eq_with(a, b, caller)) {
return VmResult::Ok(false);
}
}

VmResult::Ok(true)
}
15 changes: 14 additions & 1 deletion crates/rune/src/runtime/range.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::cmp::Ordering;
use core::fmt;
use core::ops;

Expand Down Expand Up @@ -74,7 +75,6 @@ impl Range {
}
}

/// Value pointer equals implementation for a range.
pub(crate) fn eq_with(a: &Self, b: &Self, caller: &mut impl ProtocolCaller) -> VmResult<bool> {
if !vm_try!(Value::eq_with(&a.start, &b.start, caller)) {
return VmResult::Ok(false);
Expand All @@ -87,6 +87,19 @@ impl Range {
VmResult::Ok(true)
}

pub(crate) fn cmp_with(
a: &Self,
b: &Self,
caller: &mut impl ProtocolCaller,
) -> VmResult<Ordering> {
match vm_try!(Value::cmp_with(&a.start, &b.start, caller)) {
Ordering::Equal => (),
other => return VmResult::Ok(other),
}

Value::cmp_with(&a.end, &b.end, caller)
}

/// Test if the range contains the given integer.
///
/// # Examples
Expand Down
10 changes: 9 additions & 1 deletion crates/rune/src/runtime/range_from.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::cmp::Ordering;
use core::fmt;
use core::ops;

Expand Down Expand Up @@ -64,11 +65,18 @@ impl RangeFrom {
}
}

/// Value pointer equals implementation for a range.
pub(crate) fn eq_with(a: &Self, b: &Self, caller: &mut impl ProtocolCaller) -> VmResult<bool> {
VmResult::Ok(vm_try!(Value::eq_with(&a.start, &b.start, caller)))
}

pub(crate) fn cmp_with(
a: &Self,
b: &Self,
caller: &mut impl ProtocolCaller,
) -> VmResult<Ordering> {
VmResult::Ok(vm_try!(Value::cmp_with(&a.start, &b.start, caller)))
}

/// Test if the range contains the given integer.
///
/// # Examples
Expand Down
6 changes: 5 additions & 1 deletion crates/rune/src/runtime/range_full.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::cmp::Ordering;
use core::fmt;
use core::ops;

Expand Down Expand Up @@ -25,11 +26,14 @@ impl RangeFull {
Self
}

/// Value pointer equals implementation for a range.
pub(crate) fn eq_with(_: &Self, _: &Self, _: &mut impl ProtocolCaller) -> VmResult<bool> {
VmResult::Ok(true)
}

pub(crate) fn cmp_with(_: &Self, _: &Self, _: &mut impl ProtocolCaller) -> VmResult<Ordering> {
VmResult::Ok(Ordering::Equal)
}

/// Test if the range contains the given integer.
///
/// # Examples
Expand Down
15 changes: 14 additions & 1 deletion crates/rune/src/runtime/range_inclusive.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::cmp::Ordering;
use core::fmt;
use core::ops;

Expand Down Expand Up @@ -74,7 +75,6 @@ impl RangeInclusive {
}
}

/// Value pointer equals implementation for a range.
pub(crate) fn eq_with(a: &Self, b: &Self, caller: &mut impl ProtocolCaller) -> VmResult<bool> {
if !vm_try!(Value::eq_with(&a.start, &b.start, caller)) {
return VmResult::Ok(false);
Expand All @@ -87,6 +87,19 @@ impl RangeInclusive {
VmResult::Ok(true)
}

pub(crate) fn cmp_with(
a: &Self,
b: &Self,
caller: &mut impl ProtocolCaller,
) -> VmResult<Ordering> {
match vm_try!(Value::cmp_with(&a.start, &b.start, caller)) {
Ordering::Equal => (),
other => return VmResult::Ok(other),
}

Value::cmp_with(&a.end, &b.end, caller)
}

/// Test if the range contains the given integer.
///
/// # Examples
Expand Down
14 changes: 9 additions & 5 deletions crates/rune/src/runtime/range_to.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use core::cmp::Ordering;
use core::fmt;
use core::ops;

Expand Down Expand Up @@ -29,13 +30,16 @@ impl RangeTo {
Self { end }
}

/// Value pointer equals implementation for a range.
pub(crate) fn eq_with(a: &Self, b: &Self, caller: &mut impl ProtocolCaller) -> VmResult<bool> {
if !vm_try!(Value::eq_with(&a.end, &b.end, caller)) {
return VmResult::Ok(false);
}
Value::eq_with(&a.end, &b.end, caller)
}

VmResult::Ok(true)
pub(crate) fn cmp_with(
a: &Self,
b: &Self,
caller: &mut impl ProtocolCaller,
) -> VmResult<Ordering> {
Value::cmp_with(&a.end, &b.end, caller)
}

/// Test if the range contains the given integer.
Expand Down
Loading

0 comments on commit b099125

Please sign in to comment.