Skip to content

Commit 1d3351b

Browse files
committed
Implement PartialEq and Eq for LuaValue.
This is based on the rules of Lua. Two numbers are equal if they represent the same mathematical value, and strings are equal if their contents are the same. In the case of tables, they are equal only if their references are equal. For example, two different empty tables are not equal. The `gc` crate had to be extended with a method which checks whether two `gc`s point to the same object.
1 parent ad1f5ea commit 1d3351b

File tree

4 files changed

+154
-2
lines changed

4 files changed

+154
-2
lines changed

luavm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ name = "luavm"
88
path = "src/lib/mod.rs"
99

1010
[dependencies]
11-
gc = "0.3"
11+
gc = { git="https://github.com/rbartlensky/rust-gc", branch="ref-eq" }
1212
gc_derive = "0.3"
1313
luacompiler = { path="../luacompiler" }
1414
assert_float_eq = "1.1.3"

luavm/src/lib/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ pub enum LuaError {
88
IntConversionErr,
99
/// Raised when a conversion to float fails.
1010
FloatConversionErr,
11+
/// Raised when a conversion to string fails.
12+
StringConversionErr,
1113
}

luavm/src/lib/lua_values/lua_obj.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,19 @@ use errors::LuaError;
44
pub trait LuaObj {
55
/// Clones the underlying type, and returns a box of it.
66
fn clone_box(&self) -> Box<LuaObj>;
7-
/// Checks whether the underlyning type is a float or not.
7+
/// Checks whther the underlying type is a float or an int.
8+
fn is_number(&self) -> bool;
9+
/// Checks whether the underlying type is converted to a float when processed in
10+
/// arithmetic expressions.
811
fn is_float(&self) -> bool;
12+
/// Checks whether the underlying type is a string or not.
13+
fn is_string(&self) -> bool;
914
/// Converts the underlying type to an int.
1015
fn to_int(&self) -> Result<i64, LuaError>;
1116
/// Converts the underlying type to a float.
1217
fn to_float(&self) -> Result<f64, LuaError>;
18+
/// Converts the underlying type to a string.
19+
fn to_string(&self) -> Result<String, LuaError>;
1320
}
1421

1522
/// Boxes the given `LuaObj`, and returns the address of the box.
@@ -32,13 +39,25 @@ impl LuaObj for LuaInt {
3239
Ok(self.v)
3340
}
3441

42+
fn is_number(&self) -> bool {
43+
true
44+
}
45+
3546
fn is_float(&self) -> bool {
3647
false
3748
}
3849

50+
fn is_string(&self) -> bool {
51+
false
52+
}
53+
3954
fn to_float(&self) -> Result<f64, LuaError> {
4055
Ok(self.v as f64)
4156
}
57+
58+
fn to_string(&self) -> Result<String, LuaError> {
59+
Ok(self.v.to_string())
60+
}
4261
}
4362

4463
pub struct LuaFloat {
@@ -50,17 +69,29 @@ impl LuaObj for LuaFloat {
5069
Box::new(LuaFloat { v: self.v })
5170
}
5271

72+
fn is_number(&self) -> bool {
73+
true
74+
}
75+
5376
fn is_float(&self) -> bool {
5477
true
5578
}
5679

80+
fn is_string(&self) -> bool {
81+
false
82+
}
83+
5784
fn to_int(&self) -> Result<i64, LuaError> {
5885
Err(LuaError::IntConversionErr)
5986
}
6087

6188
fn to_float(&self) -> Result<f64, LuaError> {
6289
Ok(self.v)
6390
}
91+
92+
fn to_string(&self) -> Result<String, LuaError> {
93+
Ok(self.v.to_string())
94+
}
6495
}
6596

6697
pub struct LuaString {
@@ -72,15 +103,27 @@ impl LuaObj for LuaString {
72103
Box::new(LuaString { v: self.v.clone() })
73104
}
74105

106+
fn is_number(&self) -> bool {
107+
false
108+
}
109+
75110
fn is_float(&self) -> bool {
76111
true
77112
}
78113

114+
fn is_string(&self) -> bool {
115+
true
116+
}
117+
79118
fn to_int(&self) -> Result<i64, LuaError> {
80119
self.v.parse().map_err(|_| LuaError::IntConversionErr)
81120
}
82121

83122
fn to_float(&self) -> Result<f64, LuaError> {
84123
self.v.parse().map_err(|_| LuaError::FloatConversionErr)
85124
}
125+
126+
fn to_string(&self) -> Result<String, LuaError> {
127+
Ok(self.v.clone())
128+
}
86129
}

luavm/src/lib/lua_values/mod.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,21 @@ impl LuaVal {
3939
(LuaValKind::BOXED ^ self.val) as *mut Box<LuaObj>
4040
}
4141

42+
fn is_number(&self) -> bool {
43+
match self.kind() {
44+
LuaValKind::INT | LuaValKind::FLOAT => true,
45+
LuaValKind::BOXED => unsafe { (*self.as_boxed()).is_number() },
46+
_ => false,
47+
}
48+
}
49+
50+
fn is_string(&self) -> bool {
51+
match self.kind() {
52+
LuaValKind::BOXED => unsafe { (*self.as_boxed()).is_string() },
53+
_ => false,
54+
}
55+
}
56+
4257
/// Returns true if this value can be considered a float, or false otherwise.
4358
/// This method is only used in arithmetic operations.
4459
fn is_float(&self) -> bool {
@@ -75,6 +90,18 @@ impl LuaVal {
7590
}
7691
}
7792

93+
/// Attempts to convert this value to a string.
94+
pub fn to_string(&self) -> Result<String, LuaError> {
95+
match self.kind() {
96+
LuaValKind::INT => Ok(((self.val >> tagging::TAG_SHIFT) as i64).to_string()),
97+
LuaValKind::FLOAT => {
98+
Ok((unsafe { transmute::<usize, f64>(LuaValKind::FLOAT ^ self.val) }).to_string())
99+
}
100+
LuaValKind::BOXED => unsafe { (*self.as_boxed()).to_string() },
101+
_ => Err(LuaError::StringConversionErr),
102+
}
103+
}
104+
78105
/// Sets this to a new value.
79106
pub fn set(&mut self, mut val: LuaVal) {
80107
// exchange the pointers so that when `val` goes out of scope the old value
@@ -155,6 +182,25 @@ impl LuaVal {
155182
}
156183
}
157184

185+
impl PartialEq for LuaVal {
186+
fn eq(&self, other: &LuaVal) -> bool {
187+
if self.is_number() && other.is_number() {
188+
return self.to_float().unwrap() == other.to_float().unwrap();
189+
} else if self.is_string() && other.is_string() {
190+
return self.to_string().unwrap() == other.to_string().unwrap();
191+
} else if self.kind() == other.kind() {
192+
if self.kind() == LuaValKind::NIL {
193+
return true;
194+
} else if self.kind() == LuaValKind::TABLE {
195+
return unsafe { (*table_ptr(self.val)).same_ptr(&*table_ptr(other.val)) };
196+
}
197+
}
198+
false
199+
}
200+
}
201+
202+
impl Eq for LuaVal {}
203+
158204
impl From<i64> for LuaVal {
159205
/// Create an integer LuaVal.
160206
fn from(int: i64) -> Self {
@@ -743,4 +789,65 @@ mod tests {
743789
float.set(LuaVal::from(2.0));
744790
assert_ne!(float.to_float().unwrap(), float2.to_float().unwrap());
745791
}
792+
793+
fn get_eq_types() -> Vec<LuaVal> {
794+
vec![
795+
LuaVal::from(1),
796+
LuaVal::from(1.0),
797+
LuaVal::from(String::from("1.0")),
798+
LuaVal::from(LuaTable::new(HashMap::new())),
799+
]
800+
}
801+
802+
#[test]
803+
fn eq_for_ints() {
804+
let types = get_eq_types();
805+
let int = LuaVal::from(1);
806+
assert_eq!(int, types[0]);
807+
assert_eq!(int, types[1]);
808+
assert_ne!(int, types[2]);
809+
assert_ne!(int, types[3]);
810+
let int = LuaVal::from(2);
811+
for i in 0..4 {
812+
assert_ne!(int, types[i]);
813+
}
814+
}
815+
816+
#[test]
817+
fn eq_for_floats() {
818+
let types = get_eq_types();
819+
let float = LuaVal::from(1.0);
820+
assert_eq!(float, types[0]);
821+
assert_eq!(float, types[1]);
822+
assert_ne!(float, types[2]);
823+
assert_ne!(float, types[3]);
824+
let float = LuaVal::from(2.0);
825+
for i in 0..4 {
826+
assert_ne!(float, types[i]);
827+
}
828+
}
829+
830+
#[test]
831+
fn eq_for_tables() {
832+
let types = get_eq_types();
833+
let table = LuaVal::from(LuaTable::new(HashMap::new()));
834+
assert_eq!(table, table);
835+
for i in 0..4 {
836+
assert_ne!(table, types[i]);
837+
}
838+
}
839+
840+
#[test]
841+
fn eq_for_strings() {
842+
let types = get_eq_types();
843+
let string = LuaVal::from(String::from("1.0"));
844+
assert_ne!(string, types[0]);
845+
assert_ne!(string, types[1]);
846+
assert_eq!(string, types[2]);
847+
assert_ne!(string, types[3]);
848+
let string = LuaVal::from(String::from("2.0"));
849+
for i in 0..4 {
850+
assert_ne!(string, types[i]);
851+
}
852+
}
746853
}

0 commit comments

Comments
 (0)