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
use std::io::{self, Write};
use gc_arena::Collect;
use crate::{
meta_ops::{self, MetaResult},
BoxSequence, Callback, CallbackReturn, Context, Error, Execution, Sequence, SequencePoll,
Stack, Value,
};
pub fn load_io<'gc>(ctx: Context<'gc>) {
ctx.set_global(
"print",
Callback::from_fn(&ctx, |ctx, _, mut stack| {
#[derive(Debug, Copy, Clone, Eq, PartialEq, Collect)]
#[collect(require_static)]
enum Mode {
Init,
First,
Rest,
}
#[derive(Collect)]
#[collect(no_drop)]
struct PrintSeq<'gc> {
mode: Mode,
values: Vec<Value<'gc>>,
}
impl<'gc> Sequence<'gc> for PrintSeq<'gc> {
fn poll(
&mut self,
ctx: Context<'gc>,
_exec: Execution<'gc, '_>,
mut stack: Stack<'gc, '_>,
) -> Result<SequencePoll<'gc>, Error<'gc>> {
let mut stdout = io::stdout();
if self.mode == Mode::Init {
self.mode = Mode::First;
} else {
self.values.push(stack.get(0));
}
stack.clear();
while let Some(value) = self.values.pop() {
match meta_ops::tostring(ctx, value)? {
MetaResult::Value(v) => {
if self.mode == Mode::First {
self.mode = Mode::Rest;
} else {
stdout.write_all(&b"\t"[..])?;
}
v.display(&mut stdout)?
}
MetaResult::Call(call) => {
stack.extend(call.args);
return Ok(SequencePoll::Call {
function: call.function,
is_tail: false,
});
}
}
}
stdout.write_all(&b"\n"[..])?;
stdout.flush()?;
Ok(SequencePoll::Return)
}
}
Ok(CallbackReturn::Sequence(BoxSequence::new(
&ctx,
PrintSeq {
mode: Mode::Init,
values: stack.drain(..).rev().collect(),
},
)))
}),
)
.unwrap();
}