prelude!();
use std::cmp::Ordering;
use std::sync::Arc;
#[test]
fn strut_assign() -> Result<()> {
macro_rules! test_case {
([$($op:tt)*], $protocol:ident, $derived:tt, $initial:literal, $arg:literal, $expected:literal) => {{
#[derive(Debug, Default, Any)]
struct External {
value: i64,
field: i64,
#[rune($derived)]
derived: i64,
#[rune($derived = External::custom)]
custom: i64,
}
impl External {
fn value(&mut self, value: i64) {
self.value $($op)* value;
}
fn field(&mut self, value: i64) {
self.field $($op)* value;
}
fn custom(&mut self, value: i64) {
self.custom $($op)* value;
}
}
let mut module = Module::new();
module.ty::<External>()?;
module.associated_function(&Protocol::$protocol, External::value)?;
module.field_function(&Protocol::$protocol, "field", External::field)?;
let mut context = Context::default();
context.install(module)?;
let mut sources = Sources::new();
sources.insert(Source::new(
"test",
format!(r#"
pub fn type(number) {{
number {op} {arg};
number.field {op} {arg};
number.derived {op} {arg};
number.custom {op} {arg};
}}
"#, op = stringify!($($op)*), arg = stringify!($arg)),
)?)?;
let unit = prepare(&mut sources)
.with_context(&context)
.build()?;
let unit = Arc::new(unit);
let vm = Vm::new(Arc::new(context.runtime()?), unit);
{
let mut foo = External::default();
foo.value = $initial;
foo.field = $initial;
foo.derived = $initial;
foo.custom = $initial;
let output = vm.try_clone()?.call(["type"], (&mut foo,))?;
assert_eq!(foo.value, $expected, "{} != {} (value)", foo.value, $expected);
assert_eq!(foo.field, $expected, "{} != {} (field)", foo.field, $expected);
assert_eq!(foo.derived, $expected, "{} != {} (derived)", foo.derived, $expected);
assert_eq!(foo.custom, $expected, "{} != {} (custom)", foo.custom, $expected);
output.into_unit().unwrap();
}
}};
}
test_case!([+=], ADD_ASSIGN, add_assign, 0, 3, 3);
test_case!([-=], SUB_ASSIGN, sub_assign, 4, 3, 1);
test_case!([*=], MUL_ASSIGN, mul_assign, 8, 2, 16);
test_case!([/=], DIV_ASSIGN, div_assign, 8, 3, 2);
test_case!([%=], REM_ASSIGN, rem_assign, 25, 10, 5);
test_case!([&=], BIT_AND_ASSIGN, bit_and_assign, 0b1001, 0b0011, 0b0001);
test_case!([|=], BIT_OR_ASSIGN, bit_or_assign, 0b1001, 0b0011, 0b1011);
test_case!([^=], BIT_XOR_ASSIGN, bit_xor_assign, 0b1001, 0b0011, 0b1010);
test_case!([<<=], SHL_ASSIGN, shl_assign, 0b1001, 0b0001, 0b10010);
test_case!([>>=], SHR_ASSIGN, shr_assign, 0b1001, 0b0001, 0b100);
Ok(())
}
#[test]
fn tuple_assign() -> Result<()> {
macro_rules! test_case {
([$($op:tt)*], $protocol:ident, $derived:tt, $initial:literal, $arg:literal, $expected:literal) => {{
#[derive(Debug, Default, Any)]
struct External(i64, i64, #[rune($derived)] i64, #[rune($derived = External::custom)] i64);
impl External {
fn value(&mut self, value: i64) {
self.0 $($op)* value;
}
fn field(&mut self, value: i64) {
self.1 $($op)* value;
}
fn custom(&mut self, value: i64) {
self.3 $($op)* value;
}
}
let mut module = Module::new();
module.ty::<External>()?;
module.associated_function(&Protocol::$protocol, External::value)?;
module.index_function(&Protocol::$protocol, 1, External::field)?;
let mut context = Context::default();
context.install(module)?;
let mut sources = Sources::new();
sources.insert(Source::new(
"test",
format!(r#"
pub fn type(number) {{
number {op} {arg};
number.1 {op} {arg};
number.2 {op} {arg};
number.3 {op} {arg};
}}
"#, op = stringify!($($op)*), arg = stringify!($arg)),
)?)?;
let unit = prepare(&mut sources)
.with_context(&context)
.build()?;
let unit = Arc::new(unit);
let vm = Vm::new(Arc::new(context.runtime()?), unit);
{
let mut foo = External::default();
foo.0 = $initial;
foo.1 = $initial;
foo.2 = $initial;
foo.3 = $initial;
let output = vm.try_clone()?.call(["type"], (&mut foo,))?;
assert_eq!(foo.0, $expected, "{} != {} (value .0)", foo.0, $expected);
assert_eq!(foo.1, $expected, "{} != {} (field .1)", foo.1, $expected);
assert_eq!(foo.2, $expected, "{} != {} (derived .2)", foo.2, $expected);
assert_eq!(foo.3, $expected, "{} != {} (custom .3)", foo.3, $expected);
output.into_unit().unwrap();
}
}};
}
test_case!([+=], ADD_ASSIGN, add_assign, 0, 3, 3);
test_case!([-=], SUB_ASSIGN, sub_assign, 4, 3, 1);
test_case!([*=], MUL_ASSIGN, mul_assign, 8, 2, 16);
test_case!([/=], DIV_ASSIGN, div_assign, 8, 3, 2);
test_case!([%=], REM_ASSIGN, rem_assign, 25, 10, 5);
test_case!([&=], BIT_AND_ASSIGN, bit_and_assign, 0b1001, 0b0011, 0b0001);
test_case!([|=], BIT_OR_ASSIGN, bit_or_assign, 0b1001, 0b0011, 0b1011);
test_case!([^=], BIT_XOR_ASSIGN, bit_xor_assign, 0b1001, 0b0011, 0b1010);
test_case!([<<=], SHL_ASSIGN, shl_assign, 0b1001, 0b0001, 0b10010);
test_case!([>>=], SHR_ASSIGN, shr_assign, 0b1001, 0b0001, 0b100);
Ok(())
}
#[test]
#[ignore = "assembly currently doesn't know how to handle this"]
fn struct_ops() -> Result<()> {
macro_rules! test_case {
([$($op:tt)*], $protocol:ident, $derived:tt, $initial:literal, $arg:literal, $expected:literal) => {{
#[derive(Debug, Default, Any)]
struct External {
value: i64,
field: i64,
#[rune($derived)]
derived: i64,
#[rune($derived = External::custom)]
custom: i64,
}
impl External {
fn value(&self, value: i64) -> i64 {
self.value $($op)* value
}
fn field(&self, value: i64) -> i64 {
self.field $($op)* value
}
fn custom(&self, value: i64) -> i64 {
self.custom $($op)* value
}
}
let mut module = Module::new();
module.ty::<External>()?;
module.associated_function(&Protocol::$protocol, External::value)?;
module.field_function(&Protocol::$protocol, "field", External::field)?;
let mut context = Context::default();
context.install(module)?;
let source = format!(r#"
pub fn type(number) {{
let a = number {op} {arg};
let b = number.field {op} {arg};
let c = number.derived {op} {arg};
let d = number.custom {op} {arg};
(a, b, c, d)
}}
"#, op = stringify!($($op)*), arg = stringify!($arg));
let mut sources = Sources::new();
sources.insert(Source::memory(source)?)?;
let unit = prepare(&mut sources)
.with_context(&context)
.build()?;
let unit = Arc::new(unit);
let mut vm = Vm::new(Arc::new(context.runtime()?), unit);
let mut foo = External::default();
foo.value = $initial;
foo.field = $initial;
foo.derived = $initial;
foo.custom = $initial;
let output = vm.call(["type"], (&mut foo,))?;
let (a, b, c, d) = crate::from_value::<(i64, i64, i64, i64)>(output)?;
let expected: i64 = $expected;
assert_eq!(a, expected, "{a} != {expected} (value)");
assert_eq!(b, expected, "{b} != {expected} (field)");
assert_eq!(c, expected, "{c} != {expected} (derived)");
assert_eq!(d, expected, "{d} != {expected} (custom)");
}};
}
test_case!([+], ADD, add, 0, 3, 3);
test_case!([-], SUB, sub, 4, 3, 1);
test_case!([*], MUL, mul, 8, 2, 16);
test_case!([/], DIV, div, 8, 3, 2);
test_case!([%], REM, rem, 25, 10, 5);
test_case!([&], BIT_AND, bit_and, 0b1001, 0b0011, 0b0001);
test_case!([|], BIT_OR, bit_or, 0b1001, 0b0011, 0b1011);
test_case!([^], BIT_XOR, bit_xor, 0b1001, 0b0011, 0b1010);
test_case!([<<], SHL, shl, 0b1001, 0b0001, 0b10010);
test_case!([>>], SHR, shr, 0b1001, 0b0001, 0b100);
Ok(())
}
#[test]
fn ordering_struct() -> Result<()> {
macro_rules! test_case {
([$($op:tt)*], $protocol:ident, $initial:literal, $arg:literal, $expected:literal) => {{
#[derive(Debug, Default, Any)]
struct External {
value: i64,
}
impl External {
fn value(&self, value: i64) -> Option<Ordering> {
PartialOrd::partial_cmp(&self.value, &value)
}
}
let mut module = Module::new();
module.ty::<External>()?;
module.associated_function(&Protocol::$protocol, External::value)?;
let mut context = Context::default();
context.install(module)?;
let mut sources = Sources::new();
sources.insert(Source::new(
"test",
format!(r#"
pub fn type(number) {{
number {op} {arg}
}}
"#, op = stringify!($($op)*), arg = stringify!($arg)),
)?)?;
let unit = prepare(&mut sources)
.with_context(&context)
.build()?;
let unit = Arc::new(unit);
let vm = Vm::new(Arc::new(context.runtime()?), unit);
{
let mut foo = External::default();
foo.value = $initial;
let output = vm.try_clone()?.call(["type"], (&mut foo,))?;
let a: bool = rune::from_value(output)?;
assert_eq!(a, $expected, "{} != {} (value)", foo.value, $expected);
}
}};
}
test_case!([<], PARTIAL_CMP, 1, 2, true);
test_case!([<], PARTIAL_CMP, 2, 1, false);
test_case!([>], PARTIAL_CMP, 2, 1, true);
test_case!([>], PARTIAL_CMP, 1, 2, false);
test_case!([>=], PARTIAL_CMP, 3, 2, true);
test_case!([>=], PARTIAL_CMP, 2, 2, true);
test_case!([>=], PARTIAL_CMP, 1, 2, false);
test_case!([<=], PARTIAL_CMP, 2, 3, true);
test_case!([<=], PARTIAL_CMP, 2, 2, true);
test_case!([<=], PARTIAL_CMP, 2, 1, false);
Ok(())
}
#[test]
fn eq_struct() -> Result<()> {
macro_rules! test_case {
([$($op:tt)*], $protocol:ident, $initial:literal, $arg:literal, $expected:literal) => {{
#[derive(Debug, Default, Any)]
struct External {
value: i64,
}
impl External {
fn value(&self, value: i64) -> bool {
self.value $($op)* value
}
}
let mut module = Module::new();
module.ty::<External>()?;
module.associated_function(&Protocol::$protocol, External::value)?;
let mut context = Context::default();
context.install(module)?;
let mut sources = Sources::new();
sources.insert(Source::new(
"test",
format!(r#"
pub fn type(number) {{ number {op} {arg} }}
"#, op = stringify!($($op)*), arg = stringify!($arg)),
)?)?;
let unit = prepare(&mut sources)
.with_context(&context)
.build()?;
let unit = Arc::new(unit);
let vm = Vm::new(Arc::new(context.runtime()?), unit);
{
let mut foo = External::default();
foo.value = $initial;
let output = vm.try_clone()?.call(["type"], (&mut foo,))?;
let a: bool = rune::from_value(output)?;
assert_eq!(a, $expected, "{} != {} (value)", foo.value, $expected);
}
}};
}
test_case!([==], PARTIAL_EQ, 2, 2, true);
test_case!([==], PARTIAL_EQ, 2, 1, false);
Ok(())
}