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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
//! Miscellaneous APIs related to the computer itself.

use super::error::{Error, Result};
use super::helpers::{call_buffer, call_buffer_len, call_buffer_str, call_string};
use super::Address;
use crate::panic_or_trap;
use core::num::NonZeroUsize;
use oc_wasm_sys::computer as sys;
use ordered_float::NotNan;

/// Returns the amount of world time the computer has been running, in seconds.
#[must_use = "This function is only useful for its return value"]
pub fn uptime() -> NotNan<f64> {
	// SAFETY: uptime is unconditionally safe.
	unsafe { sys::uptime() }
}

/// Returns the amount of CPU time that the computer has consumed, in seconds.
#[must_use = "This function is only useful for its return value"]
pub fn cpu_time() -> NotNan<f64> {
	// SAFETY: cpu_time is unconditionally safe.
	unsafe { sys::cpu_time() }
}

/// Returns the current in-game time and date, in game ticks.
#[must_use = "This function is only useful for its return value"]
pub fn world_time() -> u64 {
	// SAFETY: world_time is unconditionally safe.
	unsafe { sys::world_time() }
}

/// Returns the computer’s own UUID address.
#[must_use = "This function is only useful for its return value"]
pub fn address() -> Address {
	// SAFETY: address permits a writeable buffer pointer and promises to always write a valid
	// UUID. It can only fail due to MemoryFault, which, because we provide it with a valid buffer,
	// is impossible.
	let mut buffer = uuid::Bytes::default();
	unsafe { sys::address(buffer.as_mut_ptr()) };
	Address::from_bytes(buffer)
}

/// Returns the UUID address of a filesystem that lives until the computer shuts down and can
/// beused to hold temporarily files.
#[must_use = "This function is only useful for its return value"]
pub fn tmpfs_address() -> Address {
	// SAFETY: tmpfs_address permits a writeable buffer pointer and promises to always write a
	// valid UUID. It can only fail due to MemoryFault, which, because we provide it with a valid
	// buffer, is impossible.
	let mut buffer = uuid::Bytes::default();
	unsafe { sys::tmpfs_address(buffer.as_mut_ptr()) };
	Address::from_bytes(buffer)
}

/// Returns the amount, in bytes, of RAM installed in the computer.
#[must_use = "This function is only useful for its return value"]
pub fn installed_ram() -> u32 {
	// SAFETY: installed_ram is unconditionally safe.
	unsafe { sys::installed_ram() }
}

/// Returns the amount, in bytes, of free RAM in the computer.
#[must_use = "This function is only useful for its return value"]
pub fn free_ram() -> u32 {
	// SAFETY: free_ram is unconditionally safe.
	unsafe { sys::free_ram() }
}

/// Pushes a signal to the signal queue.
///
/// The `signal` parameter contains a CBOR-encoded array representing the signal, which must be a
/// mix of numbers, strings, and maps containing these types, and the first element of which must
/// be a string containing the signal name.
///
/// # Errors
/// * [`CborDecode`](Error::CborDecode) is returned if the `params` pointer is present but contains
///   an invalid or unsupported CBOR sequence.
/// * [`QueueFull`](Error::QueueFull) is returned if the computer’s signal queue is full.
pub fn push_signal(signal: &[u8]) -> Result<()> {
	Error::from_i32(
		// SAFETY: push_signal permits CBOR pointer.
		unsafe { sys::push_signal(signal.as_ptr()) },
	)?;
	Ok(())
}

/// Returns the length, in bytes, of the next signal in the signal queue.
///
/// If there is no next entry, `None` is returned.
///
/// # Panics
/// This function panics if the underlying syscall fails, because the only reasons it could fail
/// should be impossible due to the type system.
#[must_use = "This function is only useful for its return value"]
pub fn pull_signal_length() -> Option<NonZeroUsize> {
	let len =
		// SAFETY: pull_signal permits null.
		unsafe{call_buffer_len(sys::pull_signal)};
	// Can’t fail because pull_signal can only fail due to MemoryFault or StringDecode, and
	// Error::from_isize already treats those as unreachable.
	let len = len.unwrap_or_else(|_| panic_or_trap!("unreachable"));
	NonZeroUsize::new(len)
}

/// Pops a signal from the signal queue.
///
/// The `buffer` parameter identifies where to store the signal data.
///
/// If there is a signal pending, the signal data is written to `buffer` as a CBOR sequence of two
/// elements, the first being the name and the second being an array containing any additional
/// signal parameters; a slice referring to the sequence is returned; and the signal is removed
/// from the queue. If not, `None` is returned.
///
/// # Errors
/// * [`BufferTooShort`](Error::BufferTooShort) is returned if `buffer` is not large enough to hold
///   the signal data.
///
/// On error, the signal remains in the queue.
pub fn pull_signal(buffer: &mut [u8]) -> Result<Option<&mut [u8]>> {
	// SAFETY: pull_signal permits a writeable buffer pointer/length pair and promises to always
	// return the number of bytes written to it.
	let ret = unsafe { call_buffer(sys::pull_signal, buffer) }?;
	Ok(if ret.is_empty() { None } else { Some(ret) })
}

/// Begins iteration over the computer’s access control list.
///
/// Iteration over the access control list is not reentrant. Concurrent software must ensure that
/// only one access control list iteration at a time is attempted.
pub fn acl_start() {
	unsafe { sys::acl_start() }
}

/// Returns the length, in bytes, of the Minecraft username of the next allowed user in the ACL.
///
/// If there is no next entry, `None` is returned.
///
/// # Panics
/// This function panics if the underlying syscall fails, because the only reasons it could fail
/// should be impossible due to the type system.
#[must_use = "This function is only useful for its return value"]
pub fn acl_next_len() -> Option<NonZeroUsize> {
	let len =
		// SAFETY: acl_next permits null.
		unsafe{call_buffer_len(sys::acl_next)};
	// Can’t fail because acl_next can only fail due to MemoryFault or StringDecode, and
	// Error::from_isize already treats those as unreachable.
	let len = len.unwrap_or_else(|_| panic_or_trap!("unreachable"));
	NonZeroUsize::new(len)
}

/// Returns the Minecraft username of the next allowed user in the ACL.
///
/// The `buffer` parameter identifies where to store the next username.
///
/// If there is a next entry, the username is written to `buffer`, a string slice referring to it
/// is returned, and the iteration is advanced. If not, `None` is returned.
///
/// # Errors
/// * [`BufferTooShort`](Error::BufferTooShort) is returned if `buffer` is not large enough to hold
///   the component UUID.
///
/// On error, the iteration does not advance.
pub fn acl_next(buffer: &mut [u8]) -> Result<Option<&mut str>> {
	// SAFETY: acl_next permits a writeable buffer pointer/length pair and promises to always write
	// a valid UTF-8 string and return its length.
	let s = unsafe { call_buffer_str(sys::acl_next, buffer) }?;
	Ok(if s.is_empty() { None } else { Some(s) })
}

/// Grants access to the computer to a user.
///
/// The `name` parameter is the Minecraft username of the user to grant access to.
///
/// # Errors
/// * [`Other`](Error::Other) is returned if adding the user failed.
pub fn add_user(name: &str) -> Result<()> {
	// SAFETY: add_user permits a string pointer/length pair.
	unsafe { call_string(sys::add_user, Some(name)) }?;
	Ok(())
}

/// Revokes access to the computer from a user.
///
/// The `name` parameter is the Minecraft username of the user to revoke access from.
///
/// # Errors
/// * [`Other`](Error::Other) is returned if the user is not on the ACL.
pub fn remove_user(name: &str) -> Result<()> {
	// SAFETY: remove_user permits a string pointer/length pair.
	unsafe { call_string(sys::remove_user, Some(name)) }?;
	Ok(())
}

/// Returns the amount of energy stored in the computer and its network.
#[must_use = "This function is only useful for its return value"]
pub fn energy() -> NotNan<f64> {
	// SAFETY: energy is unconditionally safe.
	unsafe { sys::energy() }
}

/// Returns the maximum amount of energy that can be stored in the computer and its network.
#[must_use = "This function is only useful for its return value"]
pub fn max_energy() -> NotNan<f64> {
	// SAFETY: max_energy is unconditionally safe.
	unsafe { sys::max_energy() }
}

/// Returns the width of a Unicode character, in terminal columns.
///
/// The `ch` parameter is the character to examine.
#[must_use = "This function is only useful for its return value"]
pub fn char_width(ch: char) -> u32 {
	// SAFETY: all Unicode scalars fit in a 32-bit integer.
	let ch = ch as u32;
	// SAFETY: char_width is unconditionally safe.
	unsafe { sys::char_width(ch) }
}

/// Plays a beep.
///
/// The `frequency` parameter is the frequency, in Hz, of the beep to play. The `duration`
/// parameter is the length, in milliseconds, of the beep. Both parameters are clamped to a maximum
/// value of 32,767.
pub fn beep(frequency: u16, duration: u16) {
	// SAFETY: beep is unconditionally safe.
	unsafe { sys::beep(frequency.into(), duration.into()) }
}

/// Plays a series of beeps.
///
/// The `pattern` parameter is a Morse code beep pattern to play.
///
/// # Panics
/// This function panics if the underlying syscall fails, because the only reasons it could fail
/// should be impossible due to the type system.
pub fn beep_pattern(pattern: &str) {
	let result =
		// SAFETY: beep_pattern permits a string pointer/length pair.
		unsafe{call_string(sys::beep_pattern, Some(pattern))};
	// Can’t fail because beep_pattern can only fail due to MemoryFault or StringDecode, and
	// Error::from_i32 already treats those as unreachable.
	result.unwrap_or_else(|_| panic_or_trap!("unreachable"));
}

/// Shuts down the computer.
pub fn shutdown() -> ! {
	// SAFETY: shutdown is unconditionally safe.
	unsafe { sys::shutdown() }
}

/// Reboots the computer.
pub fn reboot() -> ! {
	// SAFETY: reboot is unconditionally safe.
	unsafe { sys::reboot() }
}

/// Halts the computer with an error.
pub fn error(error: &str) -> ! {
	// SAFETY: error accepts a string pointer/length pair; it never returns even if the
	// pointer/length pair are null or invalid.
	unsafe { sys::error(error.as_ptr(), error.len()) }
}

/// Sends a message to the debug log, if enabled.
pub fn debug(message: &str) {
	// SAFETY: debug permits a string pointer/length pair.
	let result = unsafe { call_string(sys::debug, Some(message)) };
	// Can’t fail because beep_pattern can only fail due to MemoryFault or StringDecode, and
	// Error::from_i32 already treats those as unreachable.
	result.unwrap_or_else(|_| panic_or_trap!("unreachable"));
}