1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use ruwren::{wren_module, ModuleLibrary, VMConfig};
mod ext {
use ruwren::{wren_impl, WrenObject};
#[derive(WrenObject)]
struct Unit;
#[derive(WrenObject)]
struct NewType(u8);
#[derive(WrenObject)]
struct Tuple(u8, u8, #[wren(static_member)] u8, u8);
#[derive(WrenObject, Debug, Clone)]
pub struct Foo {
bar: f64,
#[wren(static_member)]
sbar: i32,
}
#[wren_impl]
impl Foo {
#[wren_impl(allocator)]
// The return type of any method marked #[constructor] *must* be Self.
// Only one method may be marked constructor for any #[wren_impl]
fn new() -> FooClass {
FooClass { sbar: 0 }
}
// Basically, self changes statically
// constructor -> FooClass
// any method not marked "instance" -> FooClass
// any method marked "instance" -> FooWrapper
// getter means that other than self, method cannot accept any arguments
// setter means that other than self, method accept 1 argument, and return must be ()
//
// New WASM considerations:
// taking in a T means that if Wren passes in *any* other type, the runtime will flip out,
// prefer taking in Option<T> and handling the None case (the case when Wren tried to give
// you a data of a type that wasn't the one you declared)
#[wren_impl(constructor)]
fn construct(&mut self, bar: f64) -> Result<FooInstance, String> {
Ok(FooInstance { bar })
}
// This is only given a FooClass
#[wren_impl(object(ifoo))]
pub fn static_fn(&mut self, num: i32, ifoo: Option<Foo>) -> i32 {
if let Some(foo_inst) = ifoo {
eprintln!(
"got a Foo instance, is self-consistent? {}",
foo_inst.sbar == self.sbar
)
} else {
eprintln!("no Foo instance...");
}
self.sbar += num;
self.sbar
}
// a static getter
#[wren_impl(getter)]
fn sbar(class: &mut FooClass) -> i32 {
class.sbar
}
// an instance getter
#[wren_impl(instance, setter)]
fn bar(inst: &mut FooWrapper, nbar: Option<f64>) {
match nbar {
Some(val) => {
eprintln!("old {} -> new {}", inst.bar, val);
inst.bar = val;
}
None => eprintln!("arg wasn't a number, ignoring"),
}
}
#[wren_impl(instance)]
// This is given a full Foo(Wrapper), not FooClass or FooInstance
fn instance(&self) -> f64 {
dbg!(self.class.sbar);
self.bar
}
}
#[derive(WrenObject, Default, Debug)]
pub struct Teller;
#[wren_impl]
impl Teller {
#[wren_impl(object(foo_inst))]
fn tell_foo(&self, foo_inst: Option<Foo>) -> String {
match foo_inst {
Some(foo_inst) => format!("{:?}", foo_inst),
None => "that's not a Foo".to_string(),
}
}
#[wren_impl(instance, object(haha))]
fn teller(&self, haha: Teller) -> String {
format!("There nothing to tell: {:?}", haha)
}
}
#[derive(WrenObject, Default)]
pub struct Storage(#[wren(static_member)] Option<Foo>);
#[wren_impl]
impl Storage {
#[wren_impl(object(foo_inst), setter)]
fn foo(&mut self, foo_inst: Option<Foo>) {
self.0 = foo_inst;
}
#[wren_impl(getter)]
fn foo(&self) -> Option<Foo> {
self.0.clone()
}
}
}
wren_module! {
pub mod foobar {
pub crate::ext::Foo;
pub crate::ext::Teller;
pub crate::ext::Storage;
// We can't make non-pub structs pub, so
// pub crate::Tuple;
// won't work
}
}
const FOOBAR_SRC: &str = include_str!("v2_integration/foobar_full.wren");
fn main() {
let mut lib = ModuleLibrary::new();
foobar::publish_module(&mut lib);
let vm = VMConfig::new().library(&lib).build();
vm.interpret("foobar", FOOBAR_SRC).unwrap();
let res = vm.interpret("main", include_str!("v2_integration/main_full.wren"));
if let Err(err) = res {
eprintln!("{}", err);
}
}