1#![allow(clippy::too_many_arguments)]
2#![allow(clippy::doc_overindented_list_items)]
3
4pub mod draw;
127pub mod proto;
128
129#[link(wasm_import_module = "oxide")]
132extern "C" {
133 #[link_name = "api_log"]
134 fn _api_log(ptr: u32, len: u32);
135
136 #[link_name = "api_warn"]
137 fn _api_warn(ptr: u32, len: u32);
138
139 #[link_name = "api_error"]
140 fn _api_error(ptr: u32, len: u32);
141
142 #[link_name = "api_get_location"]
143 fn _api_get_location(out_ptr: u32, out_cap: u32) -> u32;
144
145 #[link_name = "api_upload_file"]
146 fn _api_upload_file(name_ptr: u32, name_cap: u32, data_ptr: u32, data_cap: u32) -> u64;
147
148 #[link_name = "api_canvas_clear"]
149 fn _api_canvas_clear(r: u32, g: u32, b: u32, a: u32);
150
151 #[link_name = "api_canvas_rect"]
152 fn _api_canvas_rect(x: f32, y: f32, w: f32, h: f32, r: u32, g: u32, b: u32, a: u32);
153
154 #[link_name = "api_canvas_circle"]
155 fn _api_canvas_circle(cx: f32, cy: f32, radius: f32, r: u32, g: u32, b: u32, a: u32);
156
157 #[link_name = "api_canvas_text"]
158 fn _api_canvas_text(
159 x: f32,
160 y: f32,
161 size: f32,
162 r: u32,
163 g: u32,
164 b: u32,
165 a: u32,
166 ptr: u32,
167 len: u32,
168 );
169
170 #[link_name = "api_canvas_line"]
171 fn _api_canvas_line(
172 x1: f32,
173 y1: f32,
174 x2: f32,
175 y2: f32,
176 r: u32,
177 g: u32,
178 b: u32,
179 a: u32,
180 thickness: f32,
181 );
182
183 #[link_name = "api_canvas_dimensions"]
184 fn _api_canvas_dimensions() -> u64;
185
186 #[link_name = "api_canvas_image"]
187 fn _api_canvas_image(x: f32, y: f32, w: f32, h: f32, data_ptr: u32, data_len: u32);
188
189 #[link_name = "api_canvas_rounded_rect"]
192 fn _api_canvas_rounded_rect(
193 x: f32,
194 y: f32,
195 w: f32,
196 h: f32,
197 radius: f32,
198 r: u32,
199 g: u32,
200 b: u32,
201 a: u32,
202 );
203
204 #[link_name = "api_canvas_arc"]
205 fn _api_canvas_arc(
206 cx: f32,
207 cy: f32,
208 radius: f32,
209 start_angle: f32,
210 end_angle: f32,
211 r: u32,
212 g: u32,
213 b: u32,
214 a: u32,
215 thickness: f32,
216 );
217
218 #[link_name = "api_canvas_bezier"]
219 fn _api_canvas_bezier(
220 x1: f32,
221 y1: f32,
222 cp1x: f32,
223 cp1y: f32,
224 cp2x: f32,
225 cp2y: f32,
226 x2: f32,
227 y2: f32,
228 r: u32,
229 g: u32,
230 b: u32,
231 a: u32,
232 thickness: f32,
233 );
234
235 #[link_name = "api_canvas_gradient"]
236 fn _api_canvas_gradient(
237 x: f32,
238 y: f32,
239 w: f32,
240 h: f32,
241 kind: u32,
242 ax: f32,
243 ay: f32,
244 bx: f32,
245 by: f32,
246 stops_ptr: u32,
247 stops_len: u32,
248 );
249
250 #[link_name = "api_canvas_save"]
253 fn _api_canvas_save();
254
255 #[link_name = "api_canvas_restore"]
256 fn _api_canvas_restore();
257
258 #[link_name = "api_canvas_transform"]
259 fn _api_canvas_transform(a: f32, b: f32, c: f32, d: f32, tx: f32, ty: f32);
260
261 #[link_name = "api_canvas_clip"]
262 fn _api_canvas_clip(x: f32, y: f32, w: f32, h: f32);
263
264 #[link_name = "api_canvas_opacity"]
265 fn _api_canvas_opacity(alpha: f32);
266
267 #[link_name = "api_storage_set"]
268 fn _api_storage_set(key_ptr: u32, key_len: u32, val_ptr: u32, val_len: u32);
269
270 #[link_name = "api_storage_get"]
271 fn _api_storage_get(key_ptr: u32, key_len: u32, out_ptr: u32, out_cap: u32) -> u32;
272
273 #[link_name = "api_storage_remove"]
274 fn _api_storage_remove(key_ptr: u32, key_len: u32);
275
276 #[link_name = "api_clipboard_write"]
277 fn _api_clipboard_write(ptr: u32, len: u32);
278
279 #[link_name = "api_clipboard_read"]
280 fn _api_clipboard_read(out_ptr: u32, out_cap: u32) -> u32;
281
282 #[link_name = "api_time_now_ms"]
283 fn _api_time_now_ms() -> u64;
284
285 #[link_name = "api_set_timeout"]
286 fn _api_set_timeout(callback_id: u32, delay_ms: u32) -> u32;
287
288 #[link_name = "api_set_interval"]
289 fn _api_set_interval(callback_id: u32, interval_ms: u32) -> u32;
290
291 #[link_name = "api_clear_timer"]
292 fn _api_clear_timer(timer_id: u32);
293
294 #[link_name = "api_request_animation_frame"]
295 fn _api_request_animation_frame(callback_id: u32) -> u32;
296
297 #[link_name = "api_cancel_animation_frame"]
298 fn _api_cancel_animation_frame(request_id: u32);
299
300 #[link_name = "api_random"]
301 fn _api_random() -> u64;
302
303 #[link_name = "api_notify"]
304 fn _api_notify(title_ptr: u32, title_len: u32, body_ptr: u32, body_len: u32);
305
306 #[link_name = "api_fetch"]
307 fn _api_fetch(
308 method_ptr: u32,
309 method_len: u32,
310 url_ptr: u32,
311 url_len: u32,
312 ct_ptr: u32,
313 ct_len: u32,
314 body_ptr: u32,
315 body_len: u32,
316 out_ptr: u32,
317 out_cap: u32,
318 ) -> i64;
319
320 #[link_name = "api_fetch_begin"]
321 fn _api_fetch_begin(
322 method_ptr: u32,
323 method_len: u32,
324 url_ptr: u32,
325 url_len: u32,
326 ct_ptr: u32,
327 ct_len: u32,
328 body_ptr: u32,
329 body_len: u32,
330 ) -> u32;
331
332 #[link_name = "api_fetch_state"]
333 fn _api_fetch_state(id: u32) -> u32;
334
335 #[link_name = "api_fetch_status"]
336 fn _api_fetch_status(id: u32) -> u32;
337
338 #[link_name = "api_fetch_recv"]
339 fn _api_fetch_recv(id: u32, out_ptr: u32, out_cap: u32) -> i64;
340
341 #[link_name = "api_fetch_error"]
342 fn _api_fetch_error(id: u32, out_ptr: u32, out_cap: u32) -> i32;
343
344 #[link_name = "api_fetch_abort"]
345 fn _api_fetch_abort(id: u32) -> i32;
346
347 #[link_name = "api_fetch_remove"]
348 fn _api_fetch_remove(id: u32);
349
350 #[link_name = "api_load_module"]
351 fn _api_load_module(url_ptr: u32, url_len: u32) -> i32;
352
353 #[link_name = "api_hash_sha256"]
354 fn _api_hash_sha256(data_ptr: u32, data_len: u32, out_ptr: u32) -> u32;
355
356 #[link_name = "api_base64_encode"]
357 fn _api_base64_encode(data_ptr: u32, data_len: u32, out_ptr: u32, out_cap: u32) -> u32;
358
359 #[link_name = "api_base64_decode"]
360 fn _api_base64_decode(data_ptr: u32, data_len: u32, out_ptr: u32, out_cap: u32) -> u32;
361
362 #[link_name = "api_kv_store_set"]
363 fn _api_kv_store_set(key_ptr: u32, key_len: u32, val_ptr: u32, val_len: u32) -> i32;
364
365 #[link_name = "api_kv_store_get"]
366 fn _api_kv_store_get(key_ptr: u32, key_len: u32, out_ptr: u32, out_cap: u32) -> i32;
367
368 #[link_name = "api_kv_store_delete"]
369 fn _api_kv_store_delete(key_ptr: u32, key_len: u32) -> i32;
370
371 #[link_name = "api_navigate"]
374 fn _api_navigate(url_ptr: u32, url_len: u32) -> i32;
375
376 #[link_name = "api_push_state"]
377 fn _api_push_state(
378 state_ptr: u32,
379 state_len: u32,
380 title_ptr: u32,
381 title_len: u32,
382 url_ptr: u32,
383 url_len: u32,
384 );
385
386 #[link_name = "api_replace_state"]
387 fn _api_replace_state(
388 state_ptr: u32,
389 state_len: u32,
390 title_ptr: u32,
391 title_len: u32,
392 url_ptr: u32,
393 url_len: u32,
394 );
395
396 #[link_name = "api_get_url"]
397 fn _api_get_url(out_ptr: u32, out_cap: u32) -> u32;
398
399 #[link_name = "api_get_state"]
400 fn _api_get_state(out_ptr: u32, out_cap: u32) -> i32;
401
402 #[link_name = "api_history_length"]
403 fn _api_history_length() -> u32;
404
405 #[link_name = "api_history_back"]
406 fn _api_history_back() -> i32;
407
408 #[link_name = "api_history_forward"]
409 fn _api_history_forward() -> i32;
410
411 #[link_name = "api_register_hyperlink"]
414 fn _api_register_hyperlink(x: f32, y: f32, w: f32, h: f32, url_ptr: u32, url_len: u32) -> i32;
415
416 #[link_name = "api_clear_hyperlinks"]
417 fn _api_clear_hyperlinks();
418
419 #[link_name = "api_mouse_position"]
422 fn _api_mouse_position() -> u64;
423
424 #[link_name = "api_mouse_button_down"]
425 fn _api_mouse_button_down(button: u32) -> u32;
426
427 #[link_name = "api_mouse_button_clicked"]
428 fn _api_mouse_button_clicked(button: u32) -> u32;
429
430 #[link_name = "api_key_down"]
431 fn _api_key_down(key: u32) -> u32;
432
433 #[link_name = "api_key_pressed"]
434 fn _api_key_pressed(key: u32) -> u32;
435
436 #[link_name = "api_scroll_delta"]
437 fn _api_scroll_delta() -> u64;
438
439 #[link_name = "api_modifiers"]
440 fn _api_modifiers() -> u32;
441
442 #[link_name = "api_ui_button"]
445 fn _api_ui_button(
446 id: u32,
447 x: f32,
448 y: f32,
449 w: f32,
450 h: f32,
451 label_ptr: u32,
452 label_len: u32,
453 ) -> u32;
454
455 #[link_name = "api_ui_checkbox"]
456 fn _api_ui_checkbox(
457 id: u32,
458 x: f32,
459 y: f32,
460 label_ptr: u32,
461 label_len: u32,
462 initial: u32,
463 ) -> u32;
464
465 #[link_name = "api_ui_slider"]
466 fn _api_ui_slider(id: u32, x: f32, y: f32, w: f32, min: f32, max: f32, initial: f32) -> f32;
467
468 #[link_name = "api_ui_text_input"]
469 fn _api_ui_text_input(
470 id: u32,
471 x: f32,
472 y: f32,
473 w: f32,
474 init_ptr: u32,
475 init_len: u32,
476 out_ptr: u32,
477 out_cap: u32,
478 ) -> u32;
479
480 #[link_name = "api_audio_play"]
483 fn _api_audio_play(data_ptr: u32, data_len: u32) -> i32;
484
485 #[link_name = "api_audio_play_url"]
486 fn _api_audio_play_url(url_ptr: u32, url_len: u32) -> i32;
487
488 #[link_name = "api_audio_detect_format"]
489 fn _api_audio_detect_format(data_ptr: u32, data_len: u32) -> u32;
490
491 #[link_name = "api_audio_play_with_format"]
492 fn _api_audio_play_with_format(data_ptr: u32, data_len: u32, format_hint: u32) -> i32;
493
494 #[link_name = "api_audio_last_url_content_type"]
495 fn _api_audio_last_url_content_type(out_ptr: u32, out_cap: u32) -> u32;
496
497 #[link_name = "api_audio_pause"]
498 fn _api_audio_pause();
499
500 #[link_name = "api_audio_resume"]
501 fn _api_audio_resume();
502
503 #[link_name = "api_audio_stop"]
504 fn _api_audio_stop();
505
506 #[link_name = "api_audio_set_volume"]
507 fn _api_audio_set_volume(level: f32);
508
509 #[link_name = "api_audio_get_volume"]
510 fn _api_audio_get_volume() -> f32;
511
512 #[link_name = "api_audio_is_playing"]
513 fn _api_audio_is_playing() -> u32;
514
515 #[link_name = "api_audio_position"]
516 fn _api_audio_position() -> u64;
517
518 #[link_name = "api_audio_seek"]
519 fn _api_audio_seek(position_ms: u64) -> i32;
520
521 #[link_name = "api_audio_duration"]
522 fn _api_audio_duration() -> u64;
523
524 #[link_name = "api_audio_set_loop"]
525 fn _api_audio_set_loop(enabled: u32);
526
527 #[link_name = "api_audio_channel_play"]
528 fn _api_audio_channel_play(channel: u32, data_ptr: u32, data_len: u32) -> i32;
529
530 #[link_name = "api_audio_channel_play_with_format"]
531 fn _api_audio_channel_play_with_format(
532 channel: u32,
533 data_ptr: u32,
534 data_len: u32,
535 format_hint: u32,
536 ) -> i32;
537
538 #[link_name = "api_audio_channel_stop"]
539 fn _api_audio_channel_stop(channel: u32);
540
541 #[link_name = "api_audio_channel_set_volume"]
542 fn _api_audio_channel_set_volume(channel: u32, level: f32);
543
544 #[link_name = "api_video_detect_format"]
547 fn _api_video_detect_format(data_ptr: u32, data_len: u32) -> u32;
548
549 #[link_name = "api_video_load"]
550 fn _api_video_load(data_ptr: u32, data_len: u32, format_hint: u32) -> i32;
551
552 #[link_name = "api_video_load_url"]
553 fn _api_video_load_url(url_ptr: u32, url_len: u32) -> i32;
554
555 #[link_name = "api_video_last_url_content_type"]
556 fn _api_video_last_url_content_type(out_ptr: u32, out_cap: u32) -> u32;
557
558 #[link_name = "api_video_hls_variant_count"]
559 fn _api_video_hls_variant_count() -> u32;
560
561 #[link_name = "api_video_hls_variant_url"]
562 fn _api_video_hls_variant_url(index: u32, out_ptr: u32, out_cap: u32) -> u32;
563
564 #[link_name = "api_video_hls_open_variant"]
565 fn _api_video_hls_open_variant(index: u32) -> i32;
566
567 #[link_name = "api_video_play"]
568 fn _api_video_play();
569
570 #[link_name = "api_video_pause"]
571 fn _api_video_pause();
572
573 #[link_name = "api_video_stop"]
574 fn _api_video_stop();
575
576 #[link_name = "api_video_seek"]
577 fn _api_video_seek(position_ms: u64) -> i32;
578
579 #[link_name = "api_video_position"]
580 fn _api_video_position() -> u64;
581
582 #[link_name = "api_video_duration"]
583 fn _api_video_duration() -> u64;
584
585 #[link_name = "api_video_render"]
586 fn _api_video_render(x: f32, y: f32, w: f32, h: f32) -> i32;
587
588 #[link_name = "api_video_set_volume"]
589 fn _api_video_set_volume(level: f32);
590
591 #[link_name = "api_video_get_volume"]
592 fn _api_video_get_volume() -> f32;
593
594 #[link_name = "api_video_set_loop"]
595 fn _api_video_set_loop(enabled: u32);
596
597 #[link_name = "api_video_set_pip"]
598 fn _api_video_set_pip(enabled: u32);
599
600 #[link_name = "api_subtitle_load_srt"]
601 fn _api_subtitle_load_srt(ptr: u32, len: u32) -> i32;
602
603 #[link_name = "api_subtitle_load_vtt"]
604 fn _api_subtitle_load_vtt(ptr: u32, len: u32) -> i32;
605
606 #[link_name = "api_subtitle_clear"]
607 fn _api_subtitle_clear();
608
609 #[link_name = "api_camera_open"]
612 fn _api_camera_open() -> i32;
613
614 #[link_name = "api_camera_close"]
615 fn _api_camera_close();
616
617 #[link_name = "api_camera_capture_frame"]
618 fn _api_camera_capture_frame(out_ptr: u32, out_cap: u32) -> u32;
619
620 #[link_name = "api_camera_frame_dimensions"]
621 fn _api_camera_frame_dimensions() -> u64;
622
623 #[link_name = "api_microphone_open"]
624 fn _api_microphone_open() -> i32;
625
626 #[link_name = "api_microphone_close"]
627 fn _api_microphone_close();
628
629 #[link_name = "api_microphone_sample_rate"]
630 fn _api_microphone_sample_rate() -> u32;
631
632 #[link_name = "api_microphone_read_samples"]
633 fn _api_microphone_read_samples(out_ptr: u32, max_samples: u32) -> u32;
634
635 #[link_name = "api_screen_capture"]
636 fn _api_screen_capture(out_ptr: u32, out_cap: u32) -> i32;
637
638 #[link_name = "api_screen_capture_dimensions"]
639 fn _api_screen_capture_dimensions() -> u64;
640
641 #[link_name = "api_media_pipeline_stats"]
642 fn _api_media_pipeline_stats() -> u64;
643
644 #[link_name = "api_gpu_create_buffer"]
647 fn _api_gpu_create_buffer(size_lo: u32, size_hi: u32, usage: u32) -> u32;
648
649 #[link_name = "api_gpu_create_texture"]
650 fn _api_gpu_create_texture(width: u32, height: u32) -> u32;
651
652 #[link_name = "api_gpu_create_shader"]
653 fn _api_gpu_create_shader(src_ptr: u32, src_len: u32) -> u32;
654
655 #[link_name = "api_gpu_create_render_pipeline"]
656 fn _api_gpu_create_render_pipeline(
657 shader: u32,
658 vs_ptr: u32,
659 vs_len: u32,
660 fs_ptr: u32,
661 fs_len: u32,
662 ) -> u32;
663
664 #[link_name = "api_gpu_create_compute_pipeline"]
665 fn _api_gpu_create_compute_pipeline(shader: u32, ep_ptr: u32, ep_len: u32) -> u32;
666
667 #[link_name = "api_gpu_write_buffer"]
668 fn _api_gpu_write_buffer(
669 handle: u32,
670 offset_lo: u32,
671 offset_hi: u32,
672 data_ptr: u32,
673 data_len: u32,
674 ) -> u32;
675
676 #[link_name = "api_gpu_draw"]
677 fn _api_gpu_draw(pipeline: u32, target: u32, vertex_count: u32, instance_count: u32) -> u32;
678
679 #[link_name = "api_gpu_dispatch_compute"]
680 fn _api_gpu_dispatch_compute(pipeline: u32, x: u32, y: u32, z: u32) -> u32;
681
682 #[link_name = "api_gpu_destroy_buffer"]
683 fn _api_gpu_destroy_buffer(handle: u32) -> u32;
684
685 #[link_name = "api_gpu_destroy_texture"]
686 fn _api_gpu_destroy_texture(handle: u32) -> u32;
687
688 #[link_name = "api_rtc_create_peer"]
691 fn _api_rtc_create_peer(stun_ptr: u32, stun_len: u32) -> u32;
692
693 #[link_name = "api_rtc_close_peer"]
694 fn _api_rtc_close_peer(peer_id: u32) -> u32;
695
696 #[link_name = "api_rtc_create_offer"]
697 fn _api_rtc_create_offer(peer_id: u32, out_ptr: u32, out_cap: u32) -> i32;
698
699 #[link_name = "api_rtc_create_answer"]
700 fn _api_rtc_create_answer(peer_id: u32, out_ptr: u32, out_cap: u32) -> i32;
701
702 #[link_name = "api_rtc_set_local_description"]
703 fn _api_rtc_set_local_description(
704 peer_id: u32,
705 sdp_ptr: u32,
706 sdp_len: u32,
707 is_offer: u32,
708 ) -> i32;
709
710 #[link_name = "api_rtc_set_remote_description"]
711 fn _api_rtc_set_remote_description(
712 peer_id: u32,
713 sdp_ptr: u32,
714 sdp_len: u32,
715 is_offer: u32,
716 ) -> i32;
717
718 #[link_name = "api_rtc_add_ice_candidate"]
719 fn _api_rtc_add_ice_candidate(peer_id: u32, cand_ptr: u32, cand_len: u32) -> i32;
720
721 #[link_name = "api_rtc_connection_state"]
722 fn _api_rtc_connection_state(peer_id: u32) -> u32;
723
724 #[link_name = "api_rtc_poll_ice_candidate"]
725 fn _api_rtc_poll_ice_candidate(peer_id: u32, out_ptr: u32, out_cap: u32) -> i32;
726
727 #[link_name = "api_rtc_create_data_channel"]
728 fn _api_rtc_create_data_channel(
729 peer_id: u32,
730 label_ptr: u32,
731 label_len: u32,
732 ordered: u32,
733 ) -> u32;
734
735 #[link_name = "api_rtc_send"]
736 fn _api_rtc_send(
737 peer_id: u32,
738 channel_id: u32,
739 data_ptr: u32,
740 data_len: u32,
741 is_binary: u32,
742 ) -> i32;
743
744 #[link_name = "api_rtc_recv"]
745 fn _api_rtc_recv(peer_id: u32, channel_id: u32, out_ptr: u32, out_cap: u32) -> i64;
746
747 #[link_name = "api_rtc_poll_data_channel"]
748 fn _api_rtc_poll_data_channel(peer_id: u32, out_ptr: u32, out_cap: u32) -> i32;
749
750 #[link_name = "api_rtc_add_track"]
751 fn _api_rtc_add_track(peer_id: u32, kind: u32) -> u32;
752
753 #[link_name = "api_rtc_poll_track"]
754 fn _api_rtc_poll_track(peer_id: u32, out_ptr: u32, out_cap: u32) -> i32;
755
756 #[link_name = "api_rtc_signal_connect"]
757 fn _api_rtc_signal_connect(url_ptr: u32, url_len: u32) -> u32;
758
759 #[link_name = "api_rtc_signal_join_room"]
760 fn _api_rtc_signal_join_room(room_ptr: u32, room_len: u32) -> i32;
761
762 #[link_name = "api_rtc_signal_send"]
763 fn _api_rtc_signal_send(data_ptr: u32, data_len: u32) -> i32;
764
765 #[link_name = "api_rtc_signal_recv"]
766 fn _api_rtc_signal_recv(out_ptr: u32, out_cap: u32) -> i32;
767
768 #[link_name = "api_ws_connect"]
771 fn _api_ws_connect(url_ptr: u32, url_len: u32) -> u32;
772
773 #[link_name = "api_ws_send_text"]
774 fn _api_ws_send_text(id: u32, data_ptr: u32, data_len: u32) -> i32;
775
776 #[link_name = "api_ws_send_binary"]
777 fn _api_ws_send_binary(id: u32, data_ptr: u32, data_len: u32) -> i32;
778
779 #[link_name = "api_ws_recv"]
780 fn _api_ws_recv(id: u32, out_ptr: u32, out_cap: u32) -> i64;
781
782 #[link_name = "api_ws_ready_state"]
783 fn _api_ws_ready_state(id: u32) -> u32;
784
785 #[link_name = "api_ws_close"]
786 fn _api_ws_close(id: u32) -> i32;
787
788 #[link_name = "api_ws_remove"]
789 fn _api_ws_remove(id: u32);
790
791 #[link_name = "api_midi_input_count"]
794 fn _api_midi_input_count() -> u32;
795
796 #[link_name = "api_midi_output_count"]
797 fn _api_midi_output_count() -> u32;
798
799 #[link_name = "api_midi_input_name"]
800 fn _api_midi_input_name(index: u32, out_ptr: u32, out_cap: u32) -> u32;
801
802 #[link_name = "api_midi_output_name"]
803 fn _api_midi_output_name(index: u32, out_ptr: u32, out_cap: u32) -> u32;
804
805 #[link_name = "api_midi_open_input"]
806 fn _api_midi_open_input(index: u32) -> u32;
807
808 #[link_name = "api_midi_open_output"]
809 fn _api_midi_open_output(index: u32) -> u32;
810
811 #[link_name = "api_midi_send"]
812 fn _api_midi_send(handle: u32, data_ptr: u32, data_len: u32) -> i32;
813
814 #[link_name = "api_midi_recv"]
815 fn _api_midi_recv(handle: u32, out_ptr: u32, out_cap: u32) -> i32;
816
817 #[link_name = "api_midi_close"]
818 fn _api_midi_close(handle: u32);
819
820 #[link_name = "api_url_resolve"]
823 fn _api_url_resolve(
824 base_ptr: u32,
825 base_len: u32,
826 rel_ptr: u32,
827 rel_len: u32,
828 out_ptr: u32,
829 out_cap: u32,
830 ) -> i32;
831
832 #[link_name = "api_url_encode"]
833 fn _api_url_encode(input_ptr: u32, input_len: u32, out_ptr: u32, out_cap: u32) -> u32;
834
835 #[link_name = "api_url_decode"]
836 fn _api_url_decode(input_ptr: u32, input_len: u32, out_ptr: u32, out_cap: u32) -> u32;
837}
838
839pub fn log(msg: &str) {
843 unsafe { _api_log(msg.as_ptr() as u32, msg.len() as u32) }
844}
845
846pub fn warn(msg: &str) {
848 unsafe { _api_warn(msg.as_ptr() as u32, msg.len() as u32) }
849}
850
851pub fn error(msg: &str) {
853 unsafe { _api_error(msg.as_ptr() as u32, msg.len() as u32) }
854}
855
856pub fn get_location() -> String {
860 let mut buf = [0u8; 128];
861 let len = unsafe { _api_get_location(buf.as_mut_ptr() as u32, buf.len() as u32) };
862 String::from_utf8_lossy(&buf[..len as usize]).to_string()
863}
864
865pub struct UploadedFile {
869 pub name: String,
870 pub data: Vec<u8>,
871}
872
873pub fn upload_file() -> Option<UploadedFile> {
876 let mut name_buf = [0u8; 256];
877 let mut data_buf = vec![0u8; 1024 * 1024]; let result = unsafe {
880 _api_upload_file(
881 name_buf.as_mut_ptr() as u32,
882 name_buf.len() as u32,
883 data_buf.as_mut_ptr() as u32,
884 data_buf.len() as u32,
885 )
886 };
887
888 if result == 0 {
889 return None;
890 }
891
892 let name_len = (result >> 32) as usize;
893 let data_len = (result & 0xFFFF_FFFF) as usize;
894
895 Some(UploadedFile {
896 name: String::from_utf8_lossy(&name_buf[..name_len]).to_string(),
897 data: data_buf[..data_len].to_vec(),
898 })
899}
900
901pub fn canvas_clear(r: u8, g: u8, b: u8, a: u8) {
905 unsafe { _api_canvas_clear(r as u32, g as u32, b as u32, a as u32) }
906}
907
908pub fn canvas_rect(x: f32, y: f32, w: f32, h: f32, r: u8, g: u8, b: u8, a: u8) {
910 unsafe { _api_canvas_rect(x, y, w, h, r as u32, g as u32, b as u32, a as u32) }
911}
912
913pub fn canvas_circle(cx: f32, cy: f32, radius: f32, r: u8, g: u8, b: u8, a: u8) {
915 unsafe { _api_canvas_circle(cx, cy, radius, r as u32, g as u32, b as u32, a as u32) }
916}
917
918pub fn canvas_text(x: f32, y: f32, size: f32, r: u8, g: u8, b: u8, a: u8, text: &str) {
920 unsafe {
921 _api_canvas_text(
922 x,
923 y,
924 size,
925 r as u32,
926 g as u32,
927 b as u32,
928 a as u32,
929 text.as_ptr() as u32,
930 text.len() as u32,
931 )
932 }
933}
934
935pub fn canvas_line(x1: f32, y1: f32, x2: f32, y2: f32, r: u8, g: u8, b: u8, a: u8, thickness: f32) {
937 unsafe {
938 _api_canvas_line(
939 x1, y1, x2, y2, r as u32, g as u32, b as u32, a as u32, thickness,
940 )
941 }
942}
943
944pub fn canvas_dimensions() -> (u32, u32) {
946 let packed = unsafe { _api_canvas_dimensions() };
947 ((packed >> 32) as u32, (packed & 0xFFFF_FFFF) as u32)
948}
949
950pub fn canvas_image(x: f32, y: f32, w: f32, h: f32, data: &[u8]) {
953 unsafe { _api_canvas_image(x, y, w, h, data.as_ptr() as u32, data.len() as u32) }
954}
955
956pub fn canvas_rounded_rect(
960 x: f32,
961 y: f32,
962 w: f32,
963 h: f32,
964 radius: f32,
965 r: u8,
966 g: u8,
967 b: u8,
968 a: u8,
969) {
970 unsafe { _api_canvas_rounded_rect(x, y, w, h, radius, r as u32, g as u32, b as u32, a as u32) }
971}
972
973pub fn canvas_arc(
975 cx: f32,
976 cy: f32,
977 radius: f32,
978 start_angle: f32,
979 end_angle: f32,
980 r: u8,
981 g: u8,
982 b: u8,
983 a: u8,
984 thickness: f32,
985) {
986 unsafe {
987 _api_canvas_arc(
988 cx,
989 cy,
990 radius,
991 start_angle,
992 end_angle,
993 r as u32,
994 g as u32,
995 b as u32,
996 a as u32,
997 thickness,
998 )
999 }
1000}
1001
1002pub fn canvas_bezier(
1004 x1: f32,
1005 y1: f32,
1006 cp1x: f32,
1007 cp1y: f32,
1008 cp2x: f32,
1009 cp2y: f32,
1010 x2: f32,
1011 y2: f32,
1012 r: u8,
1013 g: u8,
1014 b: u8,
1015 a: u8,
1016 thickness: f32,
1017) {
1018 unsafe {
1019 _api_canvas_bezier(
1020 x1, y1, cp1x, cp1y, cp2x, cp2y, x2, y2, r as u32, g as u32, b as u32, a as u32,
1021 thickness,
1022 )
1023 }
1024}
1025
1026pub const GRADIENT_LINEAR: u32 = 0;
1028pub const GRADIENT_RADIAL: u32 = 1;
1029
1030pub fn canvas_gradient(
1037 x: f32,
1038 y: f32,
1039 w: f32,
1040 h: f32,
1041 kind: u32,
1042 ax: f32,
1043 ay: f32,
1044 bx: f32,
1045 by: f32,
1046 stops: &[(f32, u8, u8, u8, u8)],
1047) {
1048 let mut buf = Vec::with_capacity(stops.len() * 8);
1049 for &(offset, r, g, b, a) in stops {
1050 buf.extend_from_slice(&offset.to_le_bytes());
1051 buf.push(r);
1052 buf.push(g);
1053 buf.push(b);
1054 buf.push(a);
1055 }
1056 unsafe {
1057 _api_canvas_gradient(
1058 x,
1059 y,
1060 w,
1061 h,
1062 kind,
1063 ax,
1064 ay,
1065 bx,
1066 by,
1067 buf.as_ptr() as u32,
1068 buf.len() as u32,
1069 )
1070 }
1071}
1072
1073pub fn canvas_save() {
1078 unsafe { _api_canvas_save() }
1079}
1080
1081pub fn canvas_restore() {
1083 unsafe { _api_canvas_restore() }
1084}
1085
1086pub fn canvas_transform(a: f32, b: f32, c: f32, d: f32, tx: f32, ty: f32) {
1097 unsafe { _api_canvas_transform(a, b, c, d, tx, ty) }
1098}
1099
1100pub fn canvas_clip(x: f32, y: f32, w: f32, h: f32) {
1103 unsafe { _api_canvas_clip(x, y, w, h) }
1104}
1105
1106pub fn canvas_opacity(alpha: f32) {
1109 unsafe { _api_canvas_opacity(alpha) }
1110}
1111
1112pub mod gpu_usage {
1116 pub const VERTEX: u32 = 0x0020;
1117 pub const INDEX: u32 = 0x0010;
1118 pub const UNIFORM: u32 = 0x0040;
1119 pub const STORAGE: u32 = 0x0080;
1120}
1121
1122pub fn gpu_create_buffer(size: u64, usage: u32) -> u32 {
1126 unsafe { _api_gpu_create_buffer(size as u32, (size >> 32) as u32, usage) }
1127}
1128
1129pub fn gpu_create_texture(width: u32, height: u32) -> u32 {
1131 unsafe { _api_gpu_create_texture(width, height) }
1132}
1133
1134pub fn gpu_create_shader(source: &str) -> u32 {
1136 unsafe { _api_gpu_create_shader(source.as_ptr() as u32, source.len() as u32) }
1137}
1138
1139pub fn gpu_create_pipeline(shader: u32, vertex_entry: &str, fragment_entry: &str) -> u32 {
1143 unsafe {
1144 _api_gpu_create_render_pipeline(
1145 shader,
1146 vertex_entry.as_ptr() as u32,
1147 vertex_entry.len() as u32,
1148 fragment_entry.as_ptr() as u32,
1149 fragment_entry.len() as u32,
1150 )
1151 }
1152}
1153
1154pub fn gpu_create_compute_pipeline(shader: u32, entry_point: &str) -> u32 {
1156 unsafe {
1157 _api_gpu_create_compute_pipeline(
1158 shader,
1159 entry_point.as_ptr() as u32,
1160 entry_point.len() as u32,
1161 )
1162 }
1163}
1164
1165pub fn gpu_write_buffer(handle: u32, offset: u64, data: &[u8]) -> bool {
1167 unsafe {
1168 _api_gpu_write_buffer(
1169 handle,
1170 offset as u32,
1171 (offset >> 32) as u32,
1172 data.as_ptr() as u32,
1173 data.len() as u32,
1174 ) != 0
1175 }
1176}
1177
1178pub fn gpu_draw(
1180 pipeline: u32,
1181 target_texture: u32,
1182 vertex_count: u32,
1183 instance_count: u32,
1184) -> bool {
1185 unsafe { _api_gpu_draw(pipeline, target_texture, vertex_count, instance_count) != 0 }
1186}
1187
1188pub fn gpu_dispatch_compute(pipeline: u32, x: u32, y: u32, z: u32) -> bool {
1190 unsafe { _api_gpu_dispatch_compute(pipeline, x, y, z) != 0 }
1191}
1192
1193pub fn gpu_destroy_buffer(handle: u32) -> bool {
1195 unsafe { _api_gpu_destroy_buffer(handle) != 0 }
1196}
1197
1198pub fn gpu_destroy_texture(handle: u32) -> bool {
1200 unsafe { _api_gpu_destroy_texture(handle) != 0 }
1201}
1202
1203pub fn storage_set(key: &str, value: &str) {
1207 unsafe {
1208 _api_storage_set(
1209 key.as_ptr() as u32,
1210 key.len() as u32,
1211 value.as_ptr() as u32,
1212 value.len() as u32,
1213 )
1214 }
1215}
1216
1217pub fn storage_get(key: &str) -> String {
1219 let mut buf = [0u8; 4096];
1220 let len = unsafe {
1221 _api_storage_get(
1222 key.as_ptr() as u32,
1223 key.len() as u32,
1224 buf.as_mut_ptr() as u32,
1225 buf.len() as u32,
1226 )
1227 };
1228 String::from_utf8_lossy(&buf[..len as usize]).to_string()
1229}
1230
1231pub fn storage_remove(key: &str) {
1233 unsafe { _api_storage_remove(key.as_ptr() as u32, key.len() as u32) }
1234}
1235
1236pub fn clipboard_write(text: &str) {
1240 unsafe { _api_clipboard_write(text.as_ptr() as u32, text.len() as u32) }
1241}
1242
1243pub fn clipboard_read() -> String {
1245 let mut buf = [0u8; 4096];
1246 let len = unsafe { _api_clipboard_read(buf.as_mut_ptr() as u32, buf.len() as u32) };
1247 String::from_utf8_lossy(&buf[..len as usize]).to_string()
1248}
1249
1250pub fn time_now_ms() -> u64 {
1254 unsafe { _api_time_now_ms() }
1255}
1256
1257pub fn set_timeout(callback_id: u32, delay_ms: u32) -> u32 {
1261 unsafe { _api_set_timeout(callback_id, delay_ms) }
1262}
1263
1264pub fn set_interval(callback_id: u32, interval_ms: u32) -> u32 {
1268 unsafe { _api_set_interval(callback_id, interval_ms) }
1269}
1270
1271pub fn clear_timer(timer_id: u32) {
1273 unsafe { _api_clear_timer(timer_id) }
1274}
1275
1276pub fn request_animation_frame(callback_id: u32) -> u32 {
1282 unsafe { _api_request_animation_frame(callback_id) }
1283}
1284
1285pub fn cancel_animation_frame(request_id: u32) {
1287 unsafe { _api_cancel_animation_frame(request_id) }
1288}
1289
1290pub fn random_u64() -> u64 {
1294 unsafe { _api_random() }
1295}
1296
1297pub fn random_f64() -> f64 {
1299 (random_u64() >> 11) as f64 / (1u64 << 53) as f64
1300}
1301
1302pub fn notify(title: &str, body: &str) {
1306 unsafe {
1307 _api_notify(
1308 title.as_ptr() as u32,
1309 title.len() as u32,
1310 body.as_ptr() as u32,
1311 body.len() as u32,
1312 )
1313 }
1314}
1315
1316#[repr(u32)]
1320#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1321pub enum AudioFormat {
1322 Unknown = 0,
1324 Wav = 1,
1325 Mp3 = 2,
1326 Ogg = 3,
1327 Flac = 4,
1328}
1329
1330impl From<u32> for AudioFormat {
1331 fn from(code: u32) -> Self {
1332 match code {
1333 1 => AudioFormat::Wav,
1334 2 => AudioFormat::Mp3,
1335 3 => AudioFormat::Ogg,
1336 4 => AudioFormat::Flac,
1337 _ => AudioFormat::Unknown,
1338 }
1339 }
1340}
1341
1342impl From<AudioFormat> for u32 {
1343 fn from(f: AudioFormat) -> u32 {
1344 f as u32
1345 }
1346}
1347
1348pub fn audio_play(data: &[u8]) -> i32 {
1351 unsafe { _api_audio_play(data.as_ptr() as u32, data.len() as u32) }
1352}
1353
1354pub fn audio_detect_format(data: &[u8]) -> AudioFormat {
1356 let code = unsafe { _api_audio_detect_format(data.as_ptr() as u32, data.len() as u32) };
1357 AudioFormat::from(code)
1358}
1359
1360pub fn audio_play_with_format(data: &[u8], format: AudioFormat) -> i32 {
1363 unsafe {
1364 _api_audio_play_with_format(data.as_ptr() as u32, data.len() as u32, u32::from(format))
1365 }
1366}
1367
1368pub fn audio_play_url(url: &str) -> i32 {
1373 unsafe { _api_audio_play_url(url.as_ptr() as u32, url.len() as u32) }
1374}
1375
1376pub fn audio_last_url_content_type() -> String {
1378 let mut buf = [0u8; 512];
1379 let len =
1380 unsafe { _api_audio_last_url_content_type(buf.as_mut_ptr() as u32, buf.len() as u32) };
1381 let n = (len as usize).min(buf.len());
1382 String::from_utf8_lossy(&buf[..n]).to_string()
1383}
1384
1385pub fn audio_pause() {
1387 unsafe { _api_audio_pause() }
1388}
1389
1390pub fn audio_resume() {
1392 unsafe { _api_audio_resume() }
1393}
1394
1395pub fn audio_stop() {
1397 unsafe { _api_audio_stop() }
1398}
1399
1400pub fn audio_set_volume(level: f32) {
1402 unsafe { _api_audio_set_volume(level) }
1403}
1404
1405pub fn audio_get_volume() -> f32 {
1407 unsafe { _api_audio_get_volume() }
1408}
1409
1410pub fn audio_is_playing() -> bool {
1412 unsafe { _api_audio_is_playing() != 0 }
1413}
1414
1415pub fn audio_position() -> u64 {
1417 unsafe { _api_audio_position() }
1418}
1419
1420pub fn audio_seek(position_ms: u64) -> i32 {
1422 unsafe { _api_audio_seek(position_ms) }
1423}
1424
1425pub fn audio_duration() -> u64 {
1428 unsafe { _api_audio_duration() }
1429}
1430
1431pub fn audio_set_loop(enabled: bool) {
1434 unsafe { _api_audio_set_loop(if enabled { 1 } else { 0 }) }
1435}
1436
1437pub fn audio_channel_play(channel: u32, data: &[u8]) -> i32 {
1443 unsafe { _api_audio_channel_play(channel, data.as_ptr() as u32, data.len() as u32) }
1444}
1445
1446pub fn audio_channel_play_with_format(channel: u32, data: &[u8], format: AudioFormat) -> i32 {
1448 unsafe {
1449 _api_audio_channel_play_with_format(
1450 channel,
1451 data.as_ptr() as u32,
1452 data.len() as u32,
1453 u32::from(format),
1454 )
1455 }
1456}
1457
1458pub fn audio_channel_stop(channel: u32) {
1460 unsafe { _api_audio_channel_stop(channel) }
1461}
1462
1463pub fn audio_channel_set_volume(channel: u32, level: f32) {
1465 unsafe { _api_audio_channel_set_volume(channel, level) }
1466}
1467
1468#[repr(u32)]
1472#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1473pub enum VideoFormat {
1474 Unknown = 0,
1475 Mp4 = 1,
1476 Webm = 2,
1477 Av1 = 3,
1478}
1479
1480impl From<u32> for VideoFormat {
1481 fn from(code: u32) -> Self {
1482 match code {
1483 1 => VideoFormat::Mp4,
1484 2 => VideoFormat::Webm,
1485 3 => VideoFormat::Av1,
1486 _ => VideoFormat::Unknown,
1487 }
1488 }
1489}
1490
1491impl From<VideoFormat> for u32 {
1492 fn from(f: VideoFormat) -> u32 {
1493 f as u32
1494 }
1495}
1496
1497pub fn video_detect_format(data: &[u8]) -> VideoFormat {
1499 let code = unsafe { _api_video_detect_format(data.as_ptr() as u32, data.len() as u32) };
1500 VideoFormat::from(code)
1501}
1502
1503pub fn video_load(data: &[u8]) -> i32 {
1506 unsafe {
1507 _api_video_load(
1508 data.as_ptr() as u32,
1509 data.len() as u32,
1510 VideoFormat::Unknown as u32,
1511 )
1512 }
1513}
1514
1515pub fn video_load_with_format(data: &[u8], format: VideoFormat) -> i32 {
1517 unsafe { _api_video_load(data.as_ptr() as u32, data.len() as u32, u32::from(format)) }
1518}
1519
1520pub fn video_load_url(url: &str) -> i32 {
1522 unsafe { _api_video_load_url(url.as_ptr() as u32, url.len() as u32) }
1523}
1524
1525pub fn video_last_url_content_type() -> String {
1527 let mut buf = [0u8; 512];
1528 let len =
1529 unsafe { _api_video_last_url_content_type(buf.as_mut_ptr() as u32, buf.len() as u32) };
1530 let n = (len as usize).min(buf.len());
1531 String::from_utf8_lossy(&buf[..n]).to_string()
1532}
1533
1534pub fn video_hls_variant_count() -> u32 {
1536 unsafe { _api_video_hls_variant_count() }
1537}
1538
1539pub fn video_hls_variant_url(index: u32) -> String {
1541 let mut buf = [0u8; 2048];
1542 let len =
1543 unsafe { _api_video_hls_variant_url(index, buf.as_mut_ptr() as u32, buf.len() as u32) };
1544 let n = (len as usize).min(buf.len());
1545 String::from_utf8_lossy(&buf[..n]).to_string()
1546}
1547
1548pub fn video_hls_open_variant(index: u32) -> i32 {
1550 unsafe { _api_video_hls_open_variant(index) }
1551}
1552
1553pub fn video_play() {
1554 unsafe { _api_video_play() }
1555}
1556
1557pub fn video_pause() {
1558 unsafe { _api_video_pause() }
1559}
1560
1561pub fn video_stop() {
1562 unsafe { _api_video_stop() }
1563}
1564
1565pub fn video_seek(position_ms: u64) -> i32 {
1566 unsafe { _api_video_seek(position_ms) }
1567}
1568
1569pub fn video_position() -> u64 {
1570 unsafe { _api_video_position() }
1571}
1572
1573pub fn video_duration() -> u64 {
1574 unsafe { _api_video_duration() }
1575}
1576
1577pub fn video_render(x: f32, y: f32, w: f32, h: f32) -> i32 {
1579 unsafe { _api_video_render(x, y, w, h) }
1580}
1581
1582pub fn video_set_volume(level: f32) {
1584 unsafe { _api_video_set_volume(level) }
1585}
1586
1587pub fn video_get_volume() -> f32 {
1588 unsafe { _api_video_get_volume() }
1589}
1590
1591pub fn video_set_loop(enabled: bool) {
1592 unsafe { _api_video_set_loop(if enabled { 1 } else { 0 }) }
1593}
1594
1595pub fn video_set_pip(enabled: bool) {
1597 unsafe { _api_video_set_pip(if enabled { 1 } else { 0 }) }
1598}
1599
1600pub fn subtitle_load_srt(text: &str) -> i32 {
1602 unsafe { _api_subtitle_load_srt(text.as_ptr() as u32, text.len() as u32) }
1603}
1604
1605pub fn subtitle_load_vtt(text: &str) -> i32 {
1607 unsafe { _api_subtitle_load_vtt(text.as_ptr() as u32, text.len() as u32) }
1608}
1609
1610pub fn subtitle_clear() {
1611 unsafe { _api_subtitle_clear() }
1612}
1613
1614pub fn camera_open() -> i32 {
1620 unsafe { _api_camera_open() }
1621}
1622
1623pub fn camera_close() {
1625 unsafe { _api_camera_close() }
1626}
1627
1628pub fn camera_capture_frame(out: &mut [u8]) -> u32 {
1631 unsafe { _api_camera_capture_frame(out.as_mut_ptr() as u32, out.len() as u32) }
1632}
1633
1634pub fn camera_frame_dimensions() -> (u32, u32) {
1636 let packed = unsafe { _api_camera_frame_dimensions() };
1637 let w = (packed >> 32) as u32;
1638 let h = packed as u32;
1639 (w, h)
1640}
1641
1642pub fn microphone_open() -> i32 {
1646 unsafe { _api_microphone_open() }
1647}
1648
1649pub fn microphone_close() {
1650 unsafe { _api_microphone_close() }
1651}
1652
1653pub fn microphone_sample_rate() -> u32 {
1655 unsafe { _api_microphone_sample_rate() }
1656}
1657
1658pub fn microphone_read_samples(out: &mut [f32]) -> u32 {
1661 unsafe { _api_microphone_read_samples(out.as_mut_ptr() as u32, out.len() as u32) }
1662}
1663
1664pub fn screen_capture(out: &mut [u8]) -> Result<usize, i32> {
1668 let n = unsafe { _api_screen_capture(out.as_mut_ptr() as u32, out.len() as u32) };
1669 if n >= 0 {
1670 Ok(n as usize)
1671 } else {
1672 Err(n)
1673 }
1674}
1675
1676pub fn screen_capture_dimensions() -> (u32, u32) {
1678 let packed = unsafe { _api_screen_capture_dimensions() };
1679 let w = (packed >> 32) as u32;
1680 let h = packed as u32;
1681 (w, h)
1682}
1683
1684pub fn media_pipeline_stats() -> (u64, u32) {
1687 let packed = unsafe { _api_media_pipeline_stats() };
1688 let camera_frames = packed >> 32;
1689 let mic_ring = packed as u32;
1690 (camera_frames, mic_ring)
1691}
1692
1693pub const RTC_STATE_NEW: u32 = 0;
1697pub const RTC_STATE_CONNECTING: u32 = 1;
1699pub const RTC_STATE_CONNECTED: u32 = 2;
1701pub const RTC_STATE_DISCONNECTED: u32 = 3;
1703pub const RTC_STATE_FAILED: u32 = 4;
1705pub const RTC_STATE_CLOSED: u32 = 5;
1707
1708pub const RTC_TRACK_AUDIO: u32 = 0;
1710pub const RTC_TRACK_VIDEO: u32 = 1;
1712
1713pub struct RtcMessage {
1715 pub channel_id: u32,
1717 pub is_binary: bool,
1719 pub data: Vec<u8>,
1721}
1722
1723impl RtcMessage {
1724 pub fn text(&self) -> String {
1726 String::from_utf8_lossy(&self.data).to_string()
1727 }
1728}
1729
1730pub struct RtcDataChannelInfo {
1732 pub channel_id: u32,
1734 pub label: String,
1736}
1737
1738pub fn rtc_create_peer(stun_servers: &str) -> u32 {
1745 unsafe { _api_rtc_create_peer(stun_servers.as_ptr() as u32, stun_servers.len() as u32) }
1746}
1747
1748pub fn rtc_close_peer(peer_id: u32) -> bool {
1750 unsafe { _api_rtc_close_peer(peer_id) != 0 }
1751}
1752
1753pub fn rtc_create_offer(peer_id: u32) -> Result<String, i32> {
1757 let mut buf = vec![0u8; 16 * 1024];
1758 let n = unsafe { _api_rtc_create_offer(peer_id, buf.as_mut_ptr() as u32, buf.len() as u32) };
1759 if n < 0 {
1760 Err(n)
1761 } else {
1762 Ok(String::from_utf8_lossy(&buf[..n as usize]).to_string())
1763 }
1764}
1765
1766pub fn rtc_create_answer(peer_id: u32) -> Result<String, i32> {
1768 let mut buf = vec![0u8; 16 * 1024];
1769 let n = unsafe { _api_rtc_create_answer(peer_id, buf.as_mut_ptr() as u32, buf.len() as u32) };
1770 if n < 0 {
1771 Err(n)
1772 } else {
1773 Ok(String::from_utf8_lossy(&buf[..n as usize]).to_string())
1774 }
1775}
1776
1777pub fn rtc_set_local_description(peer_id: u32, sdp: &str, is_offer: bool) -> i32 {
1781 unsafe {
1782 _api_rtc_set_local_description(
1783 peer_id,
1784 sdp.as_ptr() as u32,
1785 sdp.len() as u32,
1786 if is_offer { 1 } else { 0 },
1787 )
1788 }
1789}
1790
1791pub fn rtc_set_remote_description(peer_id: u32, sdp: &str, is_offer: bool) -> i32 {
1793 unsafe {
1794 _api_rtc_set_remote_description(
1795 peer_id,
1796 sdp.as_ptr() as u32,
1797 sdp.len() as u32,
1798 if is_offer { 1 } else { 0 },
1799 )
1800 }
1801}
1802
1803pub fn rtc_add_ice_candidate(peer_id: u32, candidate_json: &str) -> i32 {
1805 unsafe {
1806 _api_rtc_add_ice_candidate(
1807 peer_id,
1808 candidate_json.as_ptr() as u32,
1809 candidate_json.len() as u32,
1810 )
1811 }
1812}
1813
1814pub fn rtc_connection_state(peer_id: u32) -> u32 {
1816 unsafe { _api_rtc_connection_state(peer_id) }
1817}
1818
1819pub fn rtc_poll_ice_candidate(peer_id: u32) -> Option<String> {
1822 let mut buf = vec![0u8; 4096];
1823 let n =
1824 unsafe { _api_rtc_poll_ice_candidate(peer_id, buf.as_mut_ptr() as u32, buf.len() as u32) };
1825 if n <= 0 {
1826 None
1827 } else {
1828 Some(String::from_utf8_lossy(&buf[..n as usize]).to_string())
1829 }
1830}
1831
1832pub fn rtc_create_data_channel(peer_id: u32, label: &str, ordered: bool) -> u32 {
1837 unsafe {
1838 _api_rtc_create_data_channel(
1839 peer_id,
1840 label.as_ptr() as u32,
1841 label.len() as u32,
1842 if ordered { 1 } else { 0 },
1843 )
1844 }
1845}
1846
1847pub fn rtc_send_text(peer_id: u32, channel_id: u32, text: &str) -> i32 {
1849 unsafe {
1850 _api_rtc_send(
1851 peer_id,
1852 channel_id,
1853 text.as_ptr() as u32,
1854 text.len() as u32,
1855 0,
1856 )
1857 }
1858}
1859
1860pub fn rtc_send_binary(peer_id: u32, channel_id: u32, data: &[u8]) -> i32 {
1862 unsafe {
1863 _api_rtc_send(
1864 peer_id,
1865 channel_id,
1866 data.as_ptr() as u32,
1867 data.len() as u32,
1868 1,
1869 )
1870 }
1871}
1872
1873pub fn rtc_send(peer_id: u32, channel_id: u32, data: &[u8], is_binary: bool) -> i32 {
1875 unsafe {
1876 _api_rtc_send(
1877 peer_id,
1878 channel_id,
1879 data.as_ptr() as u32,
1880 data.len() as u32,
1881 if is_binary { 1 } else { 0 },
1882 )
1883 }
1884}
1885
1886pub fn rtc_recv(peer_id: u32, channel_id: u32) -> Option<RtcMessage> {
1891 let mut buf = vec![0u8; 64 * 1024];
1892 let packed = unsafe {
1893 _api_rtc_recv(
1894 peer_id,
1895 channel_id,
1896 buf.as_mut_ptr() as u32,
1897 buf.len() as u32,
1898 )
1899 };
1900 if packed <= 0 {
1901 return None;
1902 }
1903 let packed = packed as u64;
1904 let data_len = (packed & 0xFFFF_FFFF) as usize;
1905 let is_binary = (packed >> 32) & 1 != 0;
1906 let ch = (packed >> 48) as u32;
1907 Some(RtcMessage {
1908 channel_id: ch,
1909 is_binary,
1910 data: buf[..data_len].to_vec(),
1911 })
1912}
1913
1914pub fn rtc_poll_data_channel(peer_id: u32) -> Option<RtcDataChannelInfo> {
1918 let mut buf = vec![0u8; 1024];
1919 let n =
1920 unsafe { _api_rtc_poll_data_channel(peer_id, buf.as_mut_ptr() as u32, buf.len() as u32) };
1921 if n <= 0 {
1922 return None;
1923 }
1924 let info = String::from_utf8_lossy(&buf[..n as usize]).to_string();
1925 let (id_str, label) = info.split_once(':').unwrap_or(("0", ""));
1926 Some(RtcDataChannelInfo {
1927 channel_id: id_str.parse().unwrap_or(0),
1928 label: label.to_string(),
1929 })
1930}
1931
1932pub fn rtc_add_track(peer_id: u32, kind: u32) -> u32 {
1937 unsafe { _api_rtc_add_track(peer_id, kind) }
1938}
1939
1940pub struct RtcTrackInfo {
1942 pub kind: u32,
1944 pub id: String,
1946 pub stream_id: String,
1948}
1949
1950pub fn rtc_poll_track(peer_id: u32) -> Option<RtcTrackInfo> {
1954 let mut buf = vec![0u8; 1024];
1955 let n = unsafe { _api_rtc_poll_track(peer_id, buf.as_mut_ptr() as u32, buf.len() as u32) };
1956 if n <= 0 {
1957 return None;
1958 }
1959 let info = String::from_utf8_lossy(&buf[..n as usize]).to_string();
1960 let mut parts = info.splitn(3, ':');
1961 let kind = parts.next().unwrap_or("2").parse().unwrap_or(2);
1962 let id = parts.next().unwrap_or("").to_string();
1963 let stream_id = parts.next().unwrap_or("").to_string();
1964 Some(RtcTrackInfo {
1965 kind,
1966 id,
1967 stream_id,
1968 })
1969}
1970
1971pub fn rtc_signal_connect(url: &str) -> bool {
1975 unsafe { _api_rtc_signal_connect(url.as_ptr() as u32, url.len() as u32) != 0 }
1976}
1977
1978pub fn rtc_signal_join_room(room: &str) -> i32 {
1980 unsafe { _api_rtc_signal_join_room(room.as_ptr() as u32, room.len() as u32) }
1981}
1982
1983pub fn rtc_signal_send(data: &[u8]) -> i32 {
1985 unsafe { _api_rtc_signal_send(data.as_ptr() as u32, data.len() as u32) }
1986}
1987
1988pub fn rtc_signal_recv() -> Option<Vec<u8>> {
1990 let mut buf = vec![0u8; 16 * 1024];
1991 let n = unsafe { _api_rtc_signal_recv(buf.as_mut_ptr() as u32, buf.len() as u32) };
1992 if n <= 0 {
1993 None
1994 } else {
1995 Some(buf[..n as usize].to_vec())
1996 }
1997}
1998
1999pub const WS_CONNECTING: u32 = 0;
2003pub const WS_OPEN: u32 = 1;
2005pub const WS_CLOSING: u32 = 2;
2007pub const WS_CLOSED: u32 = 3;
2009
2010pub struct WsMessage {
2012 pub is_binary: bool,
2014 pub data: Vec<u8>,
2016}
2017
2018impl WsMessage {
2019 pub fn text(&self) -> String {
2021 String::from_utf8_lossy(&self.data).to_string()
2022 }
2023}
2024
2025pub fn ws_connect(url: &str) -> u32 {
2031 unsafe { _api_ws_connect(url.as_ptr() as u32, url.len() as u32) }
2032}
2033
2034pub fn ws_send_text(id: u32, text: &str) -> i32 {
2038 unsafe { _api_ws_send_text(id, text.as_ptr() as u32, text.len() as u32) }
2039}
2040
2041pub fn ws_send_binary(id: u32, data: &[u8]) -> i32 {
2045 unsafe { _api_ws_send_binary(id, data.as_ptr() as u32, data.len() as u32) }
2046}
2047
2048pub fn ws_recv(id: u32) -> Option<WsMessage> {
2054 let mut buf = vec![0u8; 64 * 1024];
2055 let result = unsafe { _api_ws_recv(id, buf.as_mut_ptr() as u32, buf.len() as u32) };
2056 if result < 0 {
2057 return None;
2058 }
2059 let len = (result & 0xFFFF_FFFF) as usize;
2060 let is_binary = (result >> 32) & 1 == 1;
2061 Some(WsMessage {
2062 is_binary,
2063 data: buf[..len].to_vec(),
2064 })
2065}
2066
2067pub fn ws_ready_state(id: u32) -> u32 {
2071 unsafe { _api_ws_ready_state(id) }
2072}
2073
2074pub fn ws_close(id: u32) -> i32 {
2081 unsafe { _api_ws_close(id) }
2082}
2083
2084pub fn ws_remove(id: u32) {
2089 unsafe { _api_ws_remove(id) }
2090}
2091
2092pub fn midi_input_count() -> u32 {
2096 unsafe { _api_midi_input_count() }
2097}
2098
2099pub fn midi_output_count() -> u32 {
2101 unsafe { _api_midi_output_count() }
2102}
2103
2104pub fn midi_input_name(index: u32) -> String {
2108 let mut buf = [0u8; 128];
2109 let len = unsafe { _api_midi_input_name(index, buf.as_mut_ptr() as u32, buf.len() as u32) };
2110 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2111}
2112
2113pub fn midi_output_name(index: u32) -> String {
2117 let mut buf = [0u8; 128];
2118 let len = unsafe { _api_midi_output_name(index, buf.as_mut_ptr() as u32, buf.len() as u32) };
2119 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2120}
2121
2122pub fn midi_open_input(index: u32) -> u32 {
2127 unsafe { _api_midi_open_input(index) }
2128}
2129
2130pub fn midi_open_output(index: u32) -> u32 {
2134 unsafe { _api_midi_open_output(index) }
2135}
2136
2137pub fn midi_send(handle: u32, data: &[u8]) -> i32 {
2141 unsafe { _api_midi_send(handle, data.as_ptr() as u32, data.len() as u32) }
2142}
2143
2144pub fn midi_recv(handle: u32) -> Option<Vec<u8>> {
2151 let mut buf = [0u8; 256];
2152 let n = unsafe { _api_midi_recv(handle, buf.as_mut_ptr() as u32, buf.len() as u32) };
2153 if n >= 0 {
2154 return Some(buf[..n as usize].to_vec());
2155 }
2156 if n == -2 {
2158 let mut big = vec![0u8; 64 * 1024];
2159 let n2 = unsafe { _api_midi_recv(handle, big.as_mut_ptr() as u32, big.len() as u32) };
2160 if n2 >= 0 {
2161 big.truncate(n2 as usize);
2162 return Some(big);
2163 }
2164 }
2165 None
2166}
2167
2168pub fn midi_close(handle: u32) {
2170 unsafe { _api_midi_close(handle) }
2171}
2172
2173pub struct FetchResponse {
2177 pub status: u32,
2178 pub body: Vec<u8>,
2179}
2180
2181impl FetchResponse {
2182 pub fn text(&self) -> String {
2184 String::from_utf8_lossy(&self.body).to_string()
2185 }
2186}
2187
2188pub fn fetch(
2194 method: &str,
2195 url: &str,
2196 content_type: &str,
2197 body: &[u8],
2198) -> Result<FetchResponse, i64> {
2199 let mut out_buf = vec![0u8; 4 * 1024 * 1024]; let result = unsafe {
2201 _api_fetch(
2202 method.as_ptr() as u32,
2203 method.len() as u32,
2204 url.as_ptr() as u32,
2205 url.len() as u32,
2206 content_type.as_ptr() as u32,
2207 content_type.len() as u32,
2208 body.as_ptr() as u32,
2209 body.len() as u32,
2210 out_buf.as_mut_ptr() as u32,
2211 out_buf.len() as u32,
2212 )
2213 };
2214 if result < 0 {
2215 return Err(result);
2216 }
2217 let status = (result >> 32) as u32;
2218 let body_len = (result & 0xFFFF_FFFF) as usize;
2219 Ok(FetchResponse {
2220 status,
2221 body: out_buf[..body_len].to_vec(),
2222 })
2223}
2224
2225pub fn fetch_get(url: &str) -> Result<FetchResponse, i64> {
2227 fetch("GET", url, "", &[])
2228}
2229
2230pub fn fetch_post(url: &str, content_type: &str, body: &[u8]) -> Result<FetchResponse, i64> {
2232 fetch("POST", url, content_type, body)
2233}
2234
2235pub fn fetch_post_proto(url: &str, msg: &proto::ProtoEncoder) -> Result<FetchResponse, i64> {
2237 fetch("POST", url, "application/protobuf", msg.as_bytes())
2238}
2239
2240pub fn fetch_put(url: &str, content_type: &str, body: &[u8]) -> Result<FetchResponse, i64> {
2242 fetch("PUT", url, content_type, body)
2243}
2244
2245pub fn fetch_delete(url: &str) -> Result<FetchResponse, i64> {
2247 fetch("DELETE", url, "", &[])
2248}
2249
2250pub const FETCH_PENDING: u32 = 0;
2260pub const FETCH_STREAMING: u32 = 1;
2262pub const FETCH_DONE: u32 = 2;
2264pub const FETCH_ERROR: u32 = 3;
2266pub const FETCH_ABORTED: u32 = 4;
2268
2269pub enum FetchChunk {
2271 Data(Vec<u8>),
2274 Pending,
2277 End,
2279 Error,
2282}
2283
2284pub fn fetch_begin(method: &str, url: &str, content_type: &str, body: &[u8]) -> u32 {
2293 unsafe {
2294 _api_fetch_begin(
2295 method.as_ptr() as u32,
2296 method.len() as u32,
2297 url.as_ptr() as u32,
2298 url.len() as u32,
2299 content_type.as_ptr() as u32,
2300 content_type.len() as u32,
2301 body.as_ptr() as u32,
2302 body.len() as u32,
2303 )
2304 }
2305}
2306
2307pub fn fetch_begin_get(url: &str) -> u32 {
2309 fetch_begin("GET", url, "", &[])
2310}
2311
2312pub fn fetch_state(handle: u32) -> u32 {
2314 unsafe { _api_fetch_state(handle) }
2315}
2316
2317pub fn fetch_status(handle: u32) -> u32 {
2319 unsafe { _api_fetch_status(handle) }
2320}
2321
2322pub fn fetch_recv_into(handle: u32, buf: &mut [u8]) -> i64 {
2332 unsafe { _api_fetch_recv(handle, buf.as_mut_ptr() as u32, buf.len() as u32) }
2333}
2334
2335pub fn fetch_recv(handle: u32) -> FetchChunk {
2340 let mut buf = vec![0u8; 64 * 1024];
2341 let n = fetch_recv_into(handle, &mut buf);
2342 match n {
2343 -1 => FetchChunk::Pending,
2344 -2 => FetchChunk::End,
2345 -3 | -4 => FetchChunk::Error,
2346 n if n >= 0 => {
2347 buf.truncate(n as usize);
2348 FetchChunk::Data(buf)
2349 }
2350 _ => FetchChunk::Error,
2351 }
2352}
2353
2354pub fn fetch_error(handle: u32) -> Option<String> {
2356 let mut buf = [0u8; 512];
2357 let n = unsafe { _api_fetch_error(handle, buf.as_mut_ptr() as u32, buf.len() as u32) };
2358 if n < 0 {
2359 None
2360 } else {
2361 Some(String::from_utf8_lossy(&buf[..n as usize]).into_owned())
2362 }
2363}
2364
2365pub fn fetch_abort(handle: u32) -> bool {
2370 unsafe { _api_fetch_abort(handle) != 0 }
2371}
2372
2373pub fn fetch_remove(handle: u32) {
2378 unsafe { _api_fetch_remove(handle) }
2379}
2380
2381pub fn load_module(url: &str) -> i32 {
2387 unsafe { _api_load_module(url.as_ptr() as u32, url.len() as u32) }
2388}
2389
2390pub fn hash_sha256(data: &[u8]) -> [u8; 32] {
2394 let mut out = [0u8; 32];
2395 unsafe {
2396 _api_hash_sha256(
2397 data.as_ptr() as u32,
2398 data.len() as u32,
2399 out.as_mut_ptr() as u32,
2400 );
2401 }
2402 out
2403}
2404
2405pub fn hash_sha256_hex(data: &[u8]) -> String {
2407 let hash = hash_sha256(data);
2408 let mut hex = String::with_capacity(64);
2409 for byte in &hash {
2410 hex.push(HEX_CHARS[(*byte >> 4) as usize]);
2411 hex.push(HEX_CHARS[(*byte & 0x0F) as usize]);
2412 }
2413 hex
2414}
2415
2416const HEX_CHARS: [char; 16] = [
2417 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
2418];
2419
2420pub fn base64_encode(data: &[u8]) -> String {
2424 let mut buf = vec![0u8; data.len() * 4 / 3 + 8];
2425 let len = unsafe {
2426 _api_base64_encode(
2427 data.as_ptr() as u32,
2428 data.len() as u32,
2429 buf.as_mut_ptr() as u32,
2430 buf.len() as u32,
2431 )
2432 };
2433 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2434}
2435
2436pub fn base64_decode(encoded: &str) -> Vec<u8> {
2438 let mut buf = vec![0u8; encoded.len()];
2439 let len = unsafe {
2440 _api_base64_decode(
2441 encoded.as_ptr() as u32,
2442 encoded.len() as u32,
2443 buf.as_mut_ptr() as u32,
2444 buf.len() as u32,
2445 )
2446 };
2447 buf[..len as usize].to_vec()
2448}
2449
2450pub fn kv_store_set(key: &str, value: &[u8]) -> bool {
2455 let rc = unsafe {
2456 _api_kv_store_set(
2457 key.as_ptr() as u32,
2458 key.len() as u32,
2459 value.as_ptr() as u32,
2460 value.len() as u32,
2461 )
2462 };
2463 rc == 0
2464}
2465
2466pub fn kv_store_set_str(key: &str, value: &str) -> bool {
2468 kv_store_set(key, value.as_bytes())
2469}
2470
2471pub fn kv_store_get(key: &str) -> Option<Vec<u8>> {
2474 let mut buf = vec![0u8; 64 * 1024]; let rc = unsafe {
2476 _api_kv_store_get(
2477 key.as_ptr() as u32,
2478 key.len() as u32,
2479 buf.as_mut_ptr() as u32,
2480 buf.len() as u32,
2481 )
2482 };
2483 if rc < 0 {
2484 return None;
2485 }
2486 Some(buf[..rc as usize].to_vec())
2487}
2488
2489pub fn kv_store_get_str(key: &str) -> Option<String> {
2491 kv_store_get(key).map(|v| String::from_utf8_lossy(&v).into_owned())
2492}
2493
2494pub fn kv_store_delete(key: &str) -> bool {
2496 let rc = unsafe { _api_kv_store_delete(key.as_ptr() as u32, key.len() as u32) };
2497 rc == 0
2498}
2499
2500pub fn navigate(url: &str) -> i32 {
2506 unsafe { _api_navigate(url.as_ptr() as u32, url.len() as u32) }
2507}
2508
2509pub fn push_state(state: &[u8], title: &str, url: &str) {
2517 unsafe {
2518 _api_push_state(
2519 state.as_ptr() as u32,
2520 state.len() as u32,
2521 title.as_ptr() as u32,
2522 title.len() as u32,
2523 url.as_ptr() as u32,
2524 url.len() as u32,
2525 )
2526 }
2527}
2528
2529pub fn replace_state(state: &[u8], title: &str, url: &str) {
2532 unsafe {
2533 _api_replace_state(
2534 state.as_ptr() as u32,
2535 state.len() as u32,
2536 title.as_ptr() as u32,
2537 title.len() as u32,
2538 url.as_ptr() as u32,
2539 url.len() as u32,
2540 )
2541 }
2542}
2543
2544pub fn get_url() -> String {
2546 let mut buf = [0u8; 4096];
2547 let len = unsafe { _api_get_url(buf.as_mut_ptr() as u32, buf.len() as u32) };
2548 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2549}
2550
2551pub fn get_state() -> Option<Vec<u8>> {
2554 let mut buf = vec![0u8; 64 * 1024]; let rc = unsafe { _api_get_state(buf.as_mut_ptr() as u32, buf.len() as u32) };
2556 if rc < 0 {
2557 return None;
2558 }
2559 Some(buf[..rc as usize].to_vec())
2560}
2561
2562pub fn history_length() -> u32 {
2564 unsafe { _api_history_length() }
2565}
2566
2567pub fn history_back() -> bool {
2569 unsafe { _api_history_back() == 1 }
2570}
2571
2572pub fn history_forward() -> bool {
2574 unsafe { _api_history_forward() == 1 }
2575}
2576
2577pub fn register_hyperlink(x: f32, y: f32, w: f32, h: f32, url: &str) -> i32 {
2585 unsafe { _api_register_hyperlink(x, y, w, h, url.as_ptr() as u32, url.len() as u32) }
2586}
2587
2588pub fn clear_hyperlinks() {
2590 unsafe { _api_clear_hyperlinks() }
2591}
2592
2593pub fn url_resolve(base: &str, relative: &str) -> Option<String> {
2598 let mut buf = [0u8; 4096];
2599 let rc = unsafe {
2600 _api_url_resolve(
2601 base.as_ptr() as u32,
2602 base.len() as u32,
2603 relative.as_ptr() as u32,
2604 relative.len() as u32,
2605 buf.as_mut_ptr() as u32,
2606 buf.len() as u32,
2607 )
2608 };
2609 if rc < 0 {
2610 return None;
2611 }
2612 Some(String::from_utf8_lossy(&buf[..rc as usize]).to_string())
2613}
2614
2615pub fn url_encode(input: &str) -> String {
2617 let mut buf = vec![0u8; input.len() * 3 + 4];
2618 let len = unsafe {
2619 _api_url_encode(
2620 input.as_ptr() as u32,
2621 input.len() as u32,
2622 buf.as_mut_ptr() as u32,
2623 buf.len() as u32,
2624 )
2625 };
2626 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2627}
2628
2629pub fn url_decode(input: &str) -> String {
2631 let mut buf = vec![0u8; input.len() + 4];
2632 let len = unsafe {
2633 _api_url_decode(
2634 input.as_ptr() as u32,
2635 input.len() as u32,
2636 buf.as_mut_ptr() as u32,
2637 buf.len() as u32,
2638 )
2639 };
2640 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2641}
2642
2643pub fn mouse_position() -> (f32, f32) {
2647 let packed = unsafe { _api_mouse_position() };
2648 let x = f32::from_bits((packed >> 32) as u32);
2649 let y = f32::from_bits((packed & 0xFFFF_FFFF) as u32);
2650 (x, y)
2651}
2652
2653pub fn mouse_button_down(button: u32) -> bool {
2656 unsafe { _api_mouse_button_down(button) != 0 }
2657}
2658
2659pub fn mouse_button_clicked(button: u32) -> bool {
2661 unsafe { _api_mouse_button_clicked(button) != 0 }
2662}
2663
2664pub fn key_down(key: u32) -> bool {
2667 unsafe { _api_key_down(key) != 0 }
2668}
2669
2670pub fn key_pressed(key: u32) -> bool {
2672 unsafe { _api_key_pressed(key) != 0 }
2673}
2674
2675pub fn scroll_delta() -> (f32, f32) {
2677 let packed = unsafe { _api_scroll_delta() };
2678 let x = f32::from_bits((packed >> 32) as u32);
2679 let y = f32::from_bits((packed & 0xFFFF_FFFF) as u32);
2680 (x, y)
2681}
2682
2683pub fn modifiers() -> u32 {
2685 unsafe { _api_modifiers() }
2686}
2687
2688pub fn shift_held() -> bool {
2690 modifiers() & 1 != 0
2691}
2692
2693pub fn ctrl_held() -> bool {
2695 modifiers() & 2 != 0
2696}
2697
2698pub fn alt_held() -> bool {
2700 modifiers() & 4 != 0
2701}
2702
2703pub const KEY_A: u32 = 0;
2706pub const KEY_B: u32 = 1;
2707pub const KEY_C: u32 = 2;
2708pub const KEY_D: u32 = 3;
2709pub const KEY_E: u32 = 4;
2710pub const KEY_F: u32 = 5;
2711pub const KEY_G: u32 = 6;
2712pub const KEY_H: u32 = 7;
2713pub const KEY_I: u32 = 8;
2714pub const KEY_J: u32 = 9;
2715pub const KEY_K: u32 = 10;
2716pub const KEY_L: u32 = 11;
2717pub const KEY_M: u32 = 12;
2718pub const KEY_N: u32 = 13;
2719pub const KEY_O: u32 = 14;
2720pub const KEY_P: u32 = 15;
2721pub const KEY_Q: u32 = 16;
2722pub const KEY_R: u32 = 17;
2723pub const KEY_S: u32 = 18;
2724pub const KEY_T: u32 = 19;
2725pub const KEY_U: u32 = 20;
2726pub const KEY_V: u32 = 21;
2727pub const KEY_W: u32 = 22;
2728pub const KEY_X: u32 = 23;
2729pub const KEY_Y: u32 = 24;
2730pub const KEY_Z: u32 = 25;
2731pub const KEY_0: u32 = 26;
2732pub const KEY_1: u32 = 27;
2733pub const KEY_2: u32 = 28;
2734pub const KEY_3: u32 = 29;
2735pub const KEY_4: u32 = 30;
2736pub const KEY_5: u32 = 31;
2737pub const KEY_6: u32 = 32;
2738pub const KEY_7: u32 = 33;
2739pub const KEY_8: u32 = 34;
2740pub const KEY_9: u32 = 35;
2741pub const KEY_ENTER: u32 = 36;
2742pub const KEY_ESCAPE: u32 = 37;
2743pub const KEY_TAB: u32 = 38;
2744pub const KEY_BACKSPACE: u32 = 39;
2745pub const KEY_DELETE: u32 = 40;
2746pub const KEY_SPACE: u32 = 41;
2747pub const KEY_UP: u32 = 42;
2748pub const KEY_DOWN: u32 = 43;
2749pub const KEY_LEFT: u32 = 44;
2750pub const KEY_RIGHT: u32 = 45;
2751pub const KEY_HOME: u32 = 46;
2752pub const KEY_END: u32 = 47;
2753pub const KEY_PAGE_UP: u32 = 48;
2754pub const KEY_PAGE_DOWN: u32 = 49;
2755
2756pub fn ui_button(id: u32, x: f32, y: f32, w: f32, h: f32, label: &str) -> bool {
2764 unsafe { _api_ui_button(id, x, y, w, h, label.as_ptr() as u32, label.len() as u32) != 0 }
2765}
2766
2767pub fn ui_checkbox(id: u32, x: f32, y: f32, label: &str, initial: bool) -> bool {
2771 unsafe {
2772 _api_ui_checkbox(
2773 id,
2774 x,
2775 y,
2776 label.as_ptr() as u32,
2777 label.len() as u32,
2778 if initial { 1 } else { 0 },
2779 ) != 0
2780 }
2781}
2782
2783pub fn ui_slider(id: u32, x: f32, y: f32, w: f32, min: f32, max: f32, initial: f32) -> f32 {
2787 unsafe { _api_ui_slider(id, x, y, w, min, max, initial) }
2788}
2789
2790pub fn ui_text_input(id: u32, x: f32, y: f32, w: f32, initial: &str) -> String {
2794 let mut buf = [0u8; 4096];
2795 let len = unsafe {
2796 _api_ui_text_input(
2797 id,
2798 x,
2799 y,
2800 w,
2801 initial.as_ptr() as u32,
2802 initial.len() as u32,
2803 buf.as_mut_ptr() as u32,
2804 buf.len() as u32,
2805 )
2806 };
2807 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2808}