forked from LiveSplit/livesplit-core
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathlib.rs
More file actions
259 lines (238 loc) · 7.46 KB
/
lib.rs
File metadata and controls
259 lines (238 loc) · 7.46 KB
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
#![warn(
clippy::complexity,
clippy::correctness,
clippy::perf,
clippy::style,
clippy::needless_pass_by_ref_mut,
missing_docs
)]
#![allow(clippy::missing_safety_doc, non_camel_case_types, non_snake_case)]
//! mod
use std::{
cell::{Cell, RefCell},
ffi::CStr,
fs::File,
mem::ManuallyDrop,
os::raw::c_char,
ptr, slice,
};
pub mod analysis;
pub mod atomic_date_time;
pub mod attempt;
pub mod auto_splitting_runtime;
pub mod blank_space_component;
pub mod blank_space_component_state;
pub mod command_sink;
pub mod component;
pub mod current_comparison_component;
pub mod current_pace_component;
pub mod delta_component;
pub mod detailed_timer_component;
pub mod detailed_timer_component_state;
pub mod fuzzy_list;
pub mod general_layout_settings;
pub mod graph_component;
pub mod graph_component_state;
pub mod group_component;
pub mod group_component_state;
pub mod hotkey_config;
pub mod hotkey_system;
pub mod image_cache;
pub mod key_value_component_state;
pub mod lang;
pub mod layout;
pub mod layout_editor;
pub mod layout_editor_state;
pub mod layout_state;
pub mod linked_layout;
pub mod parse_run_result;
pub mod pb_chance_component;
pub mod possible_time_save_component;
pub mod potential_clean_up;
pub mod previous_segment_component;
pub mod run;
pub mod run_editor;
pub mod run_metadata;
pub mod run_metadata_custom_variable;
pub mod run_metadata_custom_variables_iter;
pub mod run_metadata_speedrun_com_variable;
pub mod run_metadata_speedrun_com_variables_iter;
pub mod segment;
pub mod segment_history;
pub mod segment_history_element;
pub mod segment_history_iter;
pub mod segment_time_component;
pub mod separator_component;
pub mod separator_component_state;
#[cfg(all(target_family = "wasm", feature = "wasm-web"))]
pub mod server_protocol;
pub mod setting_value;
pub mod shared_timer;
pub mod software_renderer;
pub mod splits_component;
pub mod splits_component_state;
pub mod sum_of_best_cleaner;
pub mod sum_of_best_component;
pub mod text_component;
pub mod text_component_state;
pub mod time;
pub mod time_span;
pub mod timer;
pub mod timer_component;
pub mod timer_component_state;
pub mod timer_read_lock;
pub mod timer_write_lock;
pub mod title_component;
pub mod title_component_state;
pub mod total_playtime_component;
#[cfg(all(target_family = "wasm", feature = "wasm-web"))]
pub mod web_command_sink;
#[cfg(all(target_family = "wasm", feature = "web-rendering"))]
pub mod web_rendering;
#[cfg(all(target_family = "wasm", feature = "therun-gg"))]
pub mod web_therun_gg;
use crate::{
run_metadata_custom_variable::RunMetadataCustomVariable,
run_metadata_speedrun_com_variable::RunMetadataSpeedrunComVariable,
segment_history_element::SegmentHistoryElement,
};
use livesplit_core::{Time, TimeSpan};
/// type
pub type Json = *const c_char;
/// type
#[expect(non_camel_case_types)]
pub type Nullablec_char = c_char;
thread_local! {
static OUTPUT_VEC: RefCell<Vec<u8>> = const { RefCell::new(Vec::new()) };
static TIME_SPAN: Cell<TimeSpan> = const { Cell::new(TimeSpan::zero()) };
static TIME: Cell<Time> = const { Cell::new(Time::new()) };
static SEGMENT_HISTORY_ELEMENT: Cell<SegmentHistoryElement> = const { Cell::new((0, Time::new())) };
static RUN_METADATA_SPEEDRUN_COM_VARIABLE: Cell<RunMetadataSpeedrunComVariable> = const { Cell::new(("", ptr::null())) };
static RUN_METADATA_CUSTOM_VARIABLE: Cell<RunMetadataCustomVariable> = const { Cell::new(("", ptr::null())) };
}
fn output_time_span(time_span: TimeSpan) -> *const TimeSpan {
TIME_SPAN.with(|output| {
output.set(time_span);
output.as_ptr() as *const TimeSpan
})
}
fn output_time(time: Time) -> *const Time {
TIME.with(|output| {
output.set(time);
output.as_ptr() as *const Time
})
}
fn output_str<S: AsRef<str>>(s: S) -> *const c_char {
output_vec(|o| {
o.extend_from_slice(s.as_ref().as_bytes());
})
}
fn with_vec<F, R>(f: F) -> R
where
F: FnOnce(&mut Vec<u8>) -> R,
{
OUTPUT_VEC.with_borrow_mut(|output| {
output.clear();
f(output)
})
}
fn output_vec<F>(f: F) -> *const c_char
where
F: FnOnce(&mut Vec<u8>),
{
OUTPUT_VEC.with_borrow_mut(|output| {
output.clear();
f(output);
output.push(0);
output.as_ptr() as *const c_char
})
}
unsafe fn slice<T>(ptr: *const T, len: usize) -> &'static [T] {
if len == 0 {
&[]
} else {
// SAFETY: The caller guarantees that `ptr` is valid for `len`.
unsafe { slice::from_raw_parts(ptr, len) }
}
}
unsafe fn slice_mut<T>(ptr: *mut T, len: usize) -> &'static mut [T] {
if len == 0 {
&mut []
} else {
// SAFETY: The caller guarantees that `ptr` is valid for `len`.
unsafe { slice::from_raw_parts_mut(ptr, len) }
}
}
unsafe fn str(s: *const c_char) -> &'static str {
if s.is_null() {
""
} else {
// SAFETY: The caller guarantees that `s` is valid.
let bytes = unsafe { CStr::from_ptr(s as _).to_bytes() };
// Depending on where the C API is used, you may be able to fully trust
// that the caller always passes valid UTF-8. On the web we use the
// `TextEncoder` which always produces valid UTF-8.
#[cfg(any(
feature = "assume-str-parameters-are-utf8",
all(target_family = "wasm", feature = "wasm-web"),
))]
{
// SAFETY: The caller guarantees that `s` is valid UTF-8.
unsafe { std::str::from_utf8_unchecked(bytes) }
}
#[cfg(not(any(
feature = "assume-str-parameters-are-utf8",
all(target_family = "wasm", feature = "wasm-web"),
)))]
{
simdutf8::basic::from_utf8(bytes).unwrap()
}
}
}
// raw file descriptor handling
#[cfg(unix)]
unsafe fn get_file(fd: i64) -> ManuallyDrop<File> {
use std::os::unix::io::FromRawFd;
// SAFETY: The caller guarantees that `fd` is valid.
ManuallyDrop::new(unsafe { File::from_raw_fd(fd as _) })
}
#[cfg(windows)]
unsafe fn get_file(handle: i64) -> ManuallyDrop<File> {
use std::os::windows::io::FromRawHandle;
// SAFETY: The caller guarantees that `handle` is valid.
ManuallyDrop::new(unsafe { File::from_raw_handle(handle as *mut () as _) })
}
#[cfg(not(any(windows, unix)))]
unsafe fn get_file(_: i64) -> ManuallyDrop<File> {
panic!("File Descriptor Parsing is not implemented for this platform");
}
/// Allocate memory.
#[cfg(all(target_family = "wasm", not(target_os = "wasi")))]
#[unsafe(no_mangle)]
pub extern "C" fn alloc(size: usize) -> *mut u8 {
if size == 0 {
std::ptr::NonNull::dangling().as_ptr()
} else {
// SAFETY: We checked that the size is not 0, so this is safe.
unsafe { std::alloc::alloc(std::alloc::Layout::from_size_align_unchecked(size, 1)) }
}
}
/// Deallocate memory.
#[cfg(all(target_family = "wasm", not(target_os = "wasi")))]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn dealloc(ptr: *mut u8, cap: usize) {
if cap != 0 {
// SAFETY: We checked that the capacity is not 0 and the caller
// guarantees that the pointer is valid to be deallocated for the given
// capacity.
unsafe {
std::alloc::dealloc(ptr, std::alloc::Layout::from_size_align_unchecked(cap, 1));
}
}
}
/// Returns the byte length of the last nul-terminated string returned on the
/// current thread. The length excludes the nul-terminator.
#[unsafe(no_mangle)]
pub extern "C" fn get_buf_len() -> usize {
OUTPUT_VEC.with_borrow(|v| v.len() - 1)
}