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
use acrylic::app::Application;
use acrylic::Size;

extern "C" {
	fn raw_log(s: *const u8, l: usize);
	fn raw_set_request_url(s: *const u8, l: usize);
	fn raw_set_request_url_prefix(s: *const u8, l: usize);
	fn raw_is_request_pending() -> usize;
}

pub fn console_log(s: &str) {
	unsafe {
		raw_log(s.as_ptr(), s.len());
	}
}

pub fn set_request_url(s: &str) {
	unsafe {
		raw_set_request_url(s.as_ptr(), s.len());
	}
}

pub fn set_request_url_prefix(s: &str) {
	unsafe {
		raw_set_request_url_prefix(s.as_ptr(), s.len());
	}
}

pub fn is_request_pending() -> bool {
	unsafe {
		raw_is_request_pending() != 0
	}
}

pub fn ensure_pending_request(app: &Application) {
	if !is_request_pending() {
		if let Some(data_request) = app.data_requests.last() {
			set_request_url(&data_request.name);
		}
	}
}

#[allow(dead_code)]
pub static mut APPLICATION: Option<Application> = None;
pub static mut RESPONSE_BYTES: Option<Vec<u8>> = None;

#[export_name = "alloc_response_bytes"]
pub extern fn alloc_response_bytes(len: usize) -> *const u8 {
	let mut vec = Vec::with_capacity(len);
	unsafe { vec.set_len(len) };
	let ptr = vec.as_ptr();
	unsafe { RESPONSE_BYTES = Some(vec) };
	ptr
}

#[export_name = "process_response"]
pub extern fn process_response(app: &mut Application) {
	let request = app.data_requests.pop().unwrap();
	let node = app.get_node(&request.node).unwrap();
	let mut node = node.lock().unwrap();
	let data = unsafe {
		RESPONSE_BYTES.as_ref().unwrap()
	};
	node.loaded(app, &request.node, &request.name, 0, data);
}

#[export_name = "drop_response_bytes"]
pub extern fn drop_response_bytes() {
	unsafe {
		RESPONSE_BYTES = None;
	}
}

#[export_name = "discard_request"]
pub extern fn discard_request(app: &mut Application) {
	app.data_requests.pop().unwrap();
}

#[export_name = "set_output_size"]
pub extern fn set_output_size(app: &mut Application, w: usize, h: usize) -> *const u8 {
	{
		let mut root = app.view.lock().expect("could not lock in set_output_size");
		let (p, _) = root.get_spot();
		root.set_spot((p, Size::new(w, h)));
	}
	app.should_recompute = true;
	app.render();
	app.output.pixels.as_ptr()
}

#[export_name = "frame"]
pub extern fn frame(app: &mut Application) {
	app.render();
	ensure_pending_request(app);
}

#[macro_export]
macro_rules! app {
	($path: literal, $init: block) => {
		#[export_name = "init"]
		pub extern fn init() -> &'static Application {
			use std::panic::set_hook;
			set_hook(Box::new(|panic_info| {
				let dbg = format!("{}", panic_info);
				platform::console_log(&dbg);
			}));
			unsafe {
				platform::set_request_url_prefix(&String::from($path));
				platform::APPLICATION = Some($init);
				&platform::APPLICATION.as_ref().unwrap()
			}
		}
	}
}