Skip to content

Commit fc822bb

Browse files
committed
Fix C3 hot reloading
1 parent fb77e5e commit fc822bb

File tree

2 files changed

+79
-12
lines changed

2 files changed

+79
-12
lines changed

plugs/c3/future.c3

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn any! FutureDone.poll(&self, any data) @dynamic {
1313
}
1414

1515
macro Future done(value) {
16-
return @tclone(FutureDone{@tclone(value)});
16+
return @clone(FutureDone{@clone(value)});
1717
}
1818

1919
struct FutureReject(Future) {
@@ -27,7 +27,7 @@ fn any! FutureReject.poll(&self, any data) @dynamic {
2727
fn Future reject(anyfault excuse) {
2828
FutureReject r = {};
2929
r.excuse = excuse;
30-
return @tclone(r);
30+
return @clone(r);
3131
}
3232

3333
def FutureThenFunction = fn Future(any result);
@@ -53,7 +53,7 @@ fn any! FutureThen.poll(&self, any data) @dynamic {
5353
}
5454

5555
macro Future Future.then(Future left, FutureThenFunction f) {
56-
return @tclone(FutureThen {
56+
return @clone(FutureThen {
5757
.left = left,
5858
.f = f
5959
});
@@ -86,7 +86,7 @@ fn any! FutureCatch.poll(&self, any data) @dynamic {
8686
// inline macro or something?), but since catch is a C3 keyword we decided to call
8787
// @catch. If it causes any problems in the future we should consider a different naming.
8888
macro Future Future.@catch(Future left, FutureCatchFunction f) {
89-
return @tclone(FutureCatch {
89+
return @clone(FutureCatch {
9090
.left = left,
9191
.f = f
9292
});

plugs/c3/plug.c3

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import std::io;
22
import std::math;
3+
import std::collections::list;
34
import raylib5::rl;
45
import future;
56

@@ -36,7 +37,7 @@ fn any! Lerp.poll(&self, any env) @dynamic {
3637
}
3738

3839
fn Future lerp(float *place, float a, float b, float duration) {
39-
return @tclone(Lerp {
40+
return @clone(Lerp {
4041
.place = place,
4142
.a = a,
4243
.b = b,
@@ -60,7 +61,7 @@ fn any! Parallel.poll(&urmom, any env) @dynamic {
6061
}
6162

6263
fn Future parallel(Future[] futures) {
63-
return @tclone(Parallel {
64+
return @clone(Parallel {
6465
.futures = futures,
6566
});
6667
}
@@ -82,33 +83,97 @@ fn any! Seq.poll(&urmom, any env) @dynamic {
8283
}
8384

8485
fn Future seq(Future[] futures) {
85-
return @tclone(Seq {
86+
return @clone(Seq {
8687
.futures = futures,
8788
});
8889
}
8990

91+
struct Patcher {
92+
List(<usz*>) lerp;
93+
List(<usz*>) par;
94+
List(<usz*>) seq;
95+
}
96+
97+
macro @fut_type_ptr(Future *x)
98+
{
99+
usz *y = (usz *) x;
100+
return y + 1;
101+
}
102+
103+
fn void Patcher.add(&urmom, Future *f) {
104+
switch(f.type) {
105+
case Lerp.typeid:
106+
urmom.lerp.push(@fut_type_ptr(f));
107+
case Parallel.typeid:
108+
urmom.par.push(@fut_type_ptr(f));
109+
case Seq.typeid:
110+
urmom.seq.push(@fut_type_ptr(f));
111+
default:
112+
unreachable("unexpected type");
113+
}
114+
}
115+
116+
macro @list_patch(list, $Type) {
117+
for (usz i = 0; i < list.len(); i++) {
118+
*list[i] = (usz) $Type.typeid;
119+
Future *f = (Future *) (list[i] - 1);
120+
$Type *ft = anycast(*f, $Type)!!; // Some dirty trickery
121+
(void)ft;
122+
}
123+
}
124+
125+
fn void Patcher.patch(&urmom) {
126+
io::printfn("Patching futures");
127+
@list_patch(urmom.lerp, Lerp);
128+
@list_patch(urmom.par, Parallel);
129+
@list_patch(urmom.seq, Seq);
130+
}
131+
132+
fn void Patcher.clear(&urmom) {
133+
urmom.lerp.clear();
134+
urmom.par.clear();
135+
urmom.seq.clear();
136+
}
137+
90138
struct State {
91139
float t1, t2;
92140
bool finished;
93141
Future anim;
142+
Patcher patcher;
94143
}
95144

96145
State *state = null;
97146

98147
fn void reset_anim()
99148
{
100-
// TODO: clean up allocator::temp() here
101-
state.anim = parallel(@tclone(Future[*] {
102-
// TODO: Tuck the whole @tclone(Future[*]{ ... }) under the future constructors
149+
// TODO: clean up allocator::heap() here
150+
// Leaky-leaky
151+
state.anim = parallel(@clone(Future[*] {
152+
// TODO: Tuck the whole @clone(Future[*]{ ... }) under the future constructors
103153
// See if variadic args can be applied here
104-
seq(@tclone(Future[*] {
154+
seq(@clone(Future[*] {
105155
lerp(&state.t1, 0, 1, CYCLE_DURATION),
106156
lerp(&state.t1, 1, 0, CYCLE_DURATION/4),
107157
})),
108-
seq(@tclone(Future[*] {
158+
seq(@clone(Future[*] {
109159
lerp(&state.t2, 0, 1, CYCLE_DURATION + CYCLE_DURATION/4),
110160
}))
111161
}));
162+
163+
state.patcher.clear();
164+
165+
// TODO: reflection to do this automatically or something
166+
// Maybe Future.traverse(fn void FutureTraverseFn(void *env, Future *f))?
167+
168+
state.patcher.add(&state.anim);
169+
Parallel *p = anycast(state.anim, Parallel)!!;
170+
foreach(&s: p.futures) {
171+
state.patcher.add(s);
172+
Seq *s1 = anycast(*s, Seq)!!;
173+
foreach(&l: s1.futures) {
174+
state.patcher.add(l);
175+
}
176+
}
112177
}
113178

114179
fn void plug_init() @export("plug_init")
@@ -125,6 +190,8 @@ fn void* plug_pre_reload() @export("plug_pre_reload")
125190
fn void plug_post_reload(void *old_state) @export("plug_post_reload")
126191
{
127192
state = old_state;
193+
194+
state.patcher.patch();
128195
}
129196

130197
fn void orbit_circle(Env env, float t, float radius, float orbit, Color color)

0 commit comments

Comments
 (0)