1#![allow(clippy::too_many_arguments)]
2#![allow(clippy::doc_overindented_list_items)]
3
4pub mod draw;
131pub mod proto;
132
133#[link(wasm_import_module = "oxide")]
136extern "C" {
137 #[link_name = "api_log"]
138 fn _api_log(ptr: u32, len: u32);
139
140 #[link_name = "api_warn"]
141 fn _api_warn(ptr: u32, len: u32);
142
143 #[link_name = "api_error"]
144 fn _api_error(ptr: u32, len: u32);
145
146 #[link_name = "api_get_location"]
147 fn _api_get_location(out_ptr: u32, out_cap: u32) -> u32;
148
149 #[link_name = "api_upload_file"]
150 fn _api_upload_file(name_ptr: u32, name_cap: u32, data_ptr: u32, data_cap: u32) -> u64;
151
152 #[link_name = "api_file_pick"]
153 fn _api_file_pick(
154 title_ptr: u32,
155 title_len: u32,
156 filters_ptr: u32,
157 filters_len: u32,
158 multiple: u32,
159 out_ptr: u32,
160 out_cap: u32,
161 ) -> i32;
162
163 #[link_name = "api_folder_pick"]
164 fn _api_folder_pick(title_ptr: u32, title_len: u32) -> u32;
165
166 #[link_name = "api_folder_entries"]
167 fn _api_folder_entries(handle: u32, out_ptr: u32, out_cap: u32) -> i32;
168
169 #[link_name = "api_file_read"]
170 fn _api_file_read(handle: u32, out_ptr: u32, out_cap: u32) -> i64;
171
172 #[link_name = "api_file_read_range"]
173 fn _api_file_read_range(
174 handle: u32,
175 offset_lo: u32,
176 offset_hi: u32,
177 len: u32,
178 out_ptr: u32,
179 out_cap: u32,
180 ) -> i64;
181
182 #[link_name = "api_file_metadata"]
183 fn _api_file_metadata(handle: u32, out_ptr: u32, out_cap: u32) -> i32;
184
185 #[link_name = "api_canvas_clear"]
186 fn _api_canvas_clear(r: u32, g: u32, b: u32, a: u32);
187
188 #[link_name = "api_canvas_rect"]
189 fn _api_canvas_rect(x: f32, y: f32, w: f32, h: f32, r: u32, g: u32, b: u32, a: u32);
190
191 #[link_name = "api_canvas_circle"]
192 fn _api_canvas_circle(cx: f32, cy: f32, radius: f32, r: u32, g: u32, b: u32, a: u32);
193
194 #[link_name = "api_canvas_text"]
195 fn _api_canvas_text(
196 x: f32,
197 y: f32,
198 size: f32,
199 r: u32,
200 g: u32,
201 b: u32,
202 a: u32,
203 ptr: u32,
204 len: u32,
205 );
206
207 #[link_name = "api_canvas_line"]
208 fn _api_canvas_line(
209 x1: f32,
210 y1: f32,
211 x2: f32,
212 y2: f32,
213 r: u32,
214 g: u32,
215 b: u32,
216 a: u32,
217 thickness: f32,
218 );
219
220 #[link_name = "api_canvas_dimensions"]
221 fn _api_canvas_dimensions() -> u64;
222
223 #[link_name = "api_canvas_image"]
224 fn _api_canvas_image(x: f32, y: f32, w: f32, h: f32, data_ptr: u32, data_len: u32);
225
226 #[link_name = "api_canvas_rounded_rect"]
229 fn _api_canvas_rounded_rect(
230 x: f32,
231 y: f32,
232 w: f32,
233 h: f32,
234 radius: f32,
235 r: u32,
236 g: u32,
237 b: u32,
238 a: u32,
239 );
240
241 #[link_name = "api_canvas_arc"]
242 fn _api_canvas_arc(
243 cx: f32,
244 cy: f32,
245 radius: f32,
246 start_angle: f32,
247 end_angle: f32,
248 r: u32,
249 g: u32,
250 b: u32,
251 a: u32,
252 thickness: f32,
253 );
254
255 #[link_name = "api_canvas_bezier"]
256 fn _api_canvas_bezier(
257 x1: f32,
258 y1: f32,
259 cp1x: f32,
260 cp1y: f32,
261 cp2x: f32,
262 cp2y: f32,
263 x2: f32,
264 y2: f32,
265 r: u32,
266 g: u32,
267 b: u32,
268 a: u32,
269 thickness: f32,
270 );
271
272 #[link_name = "api_canvas_gradient"]
273 fn _api_canvas_gradient(
274 x: f32,
275 y: f32,
276 w: f32,
277 h: f32,
278 kind: u32,
279 ax: f32,
280 ay: f32,
281 bx: f32,
282 by: f32,
283 stops_ptr: u32,
284 stops_len: u32,
285 );
286
287 #[link_name = "api_canvas_save"]
290 fn _api_canvas_save();
291
292 #[link_name = "api_canvas_restore"]
293 fn _api_canvas_restore();
294
295 #[link_name = "api_canvas_transform"]
296 fn _api_canvas_transform(a: f32, b: f32, c: f32, d: f32, tx: f32, ty: f32);
297
298 #[link_name = "api_canvas_clip"]
299 fn _api_canvas_clip(x: f32, y: f32, w: f32, h: f32);
300
301 #[link_name = "api_canvas_opacity"]
302 fn _api_canvas_opacity(alpha: f32);
303
304 #[link_name = "api_storage_set"]
305 fn _api_storage_set(key_ptr: u32, key_len: u32, val_ptr: u32, val_len: u32);
306
307 #[link_name = "api_storage_get"]
308 fn _api_storage_get(key_ptr: u32, key_len: u32, out_ptr: u32, out_cap: u32) -> u32;
309
310 #[link_name = "api_storage_remove"]
311 fn _api_storage_remove(key_ptr: u32, key_len: u32);
312
313 #[link_name = "api_clipboard_write"]
314 fn _api_clipboard_write(ptr: u32, len: u32);
315
316 #[link_name = "api_clipboard_read"]
317 fn _api_clipboard_read(out_ptr: u32, out_cap: u32) -> u32;
318
319 #[link_name = "api_time_now_ms"]
320 fn _api_time_now_ms() -> u64;
321
322 #[link_name = "api_set_timeout"]
323 fn _api_set_timeout(callback_id: u32, delay_ms: u32) -> u32;
324
325 #[link_name = "api_set_interval"]
326 fn _api_set_interval(callback_id: u32, interval_ms: u32) -> u32;
327
328 #[link_name = "api_clear_timer"]
329 fn _api_clear_timer(timer_id: u32);
330
331 #[link_name = "api_request_animation_frame"]
332 fn _api_request_animation_frame(callback_id: u32) -> u32;
333
334 #[link_name = "api_cancel_animation_frame"]
335 fn _api_cancel_animation_frame(request_id: u32);
336
337 #[link_name = "api_on_event"]
338 fn _api_on_event(type_ptr: u32, type_len: u32, callback_id: u32) -> u32;
339
340 #[link_name = "api_off_event"]
341 fn _api_off_event(listener_id: u32) -> u32;
342
343 #[link_name = "api_emit_event"]
344 fn _api_emit_event(type_ptr: u32, type_len: u32, data_ptr: u32, data_len: u32);
345
346 #[link_name = "api_event_type_len"]
347 fn _api_event_type_len() -> u32;
348
349 #[link_name = "api_event_type_read"]
350 fn _api_event_type_read(out_ptr: u32, out_cap: u32) -> u32;
351
352 #[link_name = "api_event_data_len"]
353 fn _api_event_data_len() -> u32;
354
355 #[link_name = "api_event_data_read"]
356 fn _api_event_data_read(out_ptr: u32, out_cap: u32) -> u32;
357
358 #[link_name = "api_random"]
359 fn _api_random() -> u64;
360
361 #[link_name = "api_notify"]
362 fn _api_notify(title_ptr: u32, title_len: u32, body_ptr: u32, body_len: u32);
363
364 #[link_name = "api_fetch"]
365 fn _api_fetch(
366 method_ptr: u32,
367 method_len: u32,
368 url_ptr: u32,
369 url_len: u32,
370 ct_ptr: u32,
371 ct_len: u32,
372 body_ptr: u32,
373 body_len: u32,
374 out_ptr: u32,
375 out_cap: u32,
376 ) -> i64;
377
378 #[link_name = "api_fetch_begin"]
379 fn _api_fetch_begin(
380 method_ptr: u32,
381 method_len: u32,
382 url_ptr: u32,
383 url_len: u32,
384 ct_ptr: u32,
385 ct_len: u32,
386 body_ptr: u32,
387 body_len: u32,
388 ) -> u32;
389
390 #[link_name = "api_fetch_state"]
391 fn _api_fetch_state(id: u32) -> u32;
392
393 #[link_name = "api_fetch_status"]
394 fn _api_fetch_status(id: u32) -> u32;
395
396 #[link_name = "api_fetch_recv"]
397 fn _api_fetch_recv(id: u32, out_ptr: u32, out_cap: u32) -> i64;
398
399 #[link_name = "api_fetch_error"]
400 fn _api_fetch_error(id: u32, out_ptr: u32, out_cap: u32) -> i32;
401
402 #[link_name = "api_fetch_abort"]
403 fn _api_fetch_abort(id: u32) -> i32;
404
405 #[link_name = "api_fetch_remove"]
406 fn _api_fetch_remove(id: u32);
407
408 #[link_name = "api_load_module"]
409 fn _api_load_module(url_ptr: u32, url_len: u32) -> i32;
410
411 #[link_name = "api_hash_sha256"]
412 fn _api_hash_sha256(data_ptr: u32, data_len: u32, out_ptr: u32) -> u32;
413
414 #[link_name = "api_base64_encode"]
415 fn _api_base64_encode(data_ptr: u32, data_len: u32, out_ptr: u32, out_cap: u32) -> u32;
416
417 #[link_name = "api_base64_decode"]
418 fn _api_base64_decode(data_ptr: u32, data_len: u32, out_ptr: u32, out_cap: u32) -> u32;
419
420 #[link_name = "api_kv_store_set"]
421 fn _api_kv_store_set(key_ptr: u32, key_len: u32, val_ptr: u32, val_len: u32) -> i32;
422
423 #[link_name = "api_kv_store_get"]
424 fn _api_kv_store_get(key_ptr: u32, key_len: u32, out_ptr: u32, out_cap: u32) -> i32;
425
426 #[link_name = "api_kv_store_delete"]
427 fn _api_kv_store_delete(key_ptr: u32, key_len: u32) -> i32;
428
429 #[link_name = "api_navigate"]
432 fn _api_navigate(url_ptr: u32, url_len: u32) -> i32;
433
434 #[link_name = "api_push_state"]
435 fn _api_push_state(
436 state_ptr: u32,
437 state_len: u32,
438 title_ptr: u32,
439 title_len: u32,
440 url_ptr: u32,
441 url_len: u32,
442 );
443
444 #[link_name = "api_replace_state"]
445 fn _api_replace_state(
446 state_ptr: u32,
447 state_len: u32,
448 title_ptr: u32,
449 title_len: u32,
450 url_ptr: u32,
451 url_len: u32,
452 );
453
454 #[link_name = "api_get_url"]
455 fn _api_get_url(out_ptr: u32, out_cap: u32) -> u32;
456
457 #[link_name = "api_get_state"]
458 fn _api_get_state(out_ptr: u32, out_cap: u32) -> i32;
459
460 #[link_name = "api_history_length"]
461 fn _api_history_length() -> u32;
462
463 #[link_name = "api_history_back"]
464 fn _api_history_back() -> i32;
465
466 #[link_name = "api_history_forward"]
467 fn _api_history_forward() -> i32;
468
469 #[link_name = "api_register_hyperlink"]
472 fn _api_register_hyperlink(x: f32, y: f32, w: f32, h: f32, url_ptr: u32, url_len: u32) -> i32;
473
474 #[link_name = "api_clear_hyperlinks"]
475 fn _api_clear_hyperlinks();
476
477 #[link_name = "api_mouse_position"]
480 fn _api_mouse_position() -> u64;
481
482 #[link_name = "api_mouse_button_down"]
483 fn _api_mouse_button_down(button: u32) -> u32;
484
485 #[link_name = "api_mouse_button_clicked"]
486 fn _api_mouse_button_clicked(button: u32) -> u32;
487
488 #[link_name = "api_key_down"]
489 fn _api_key_down(key: u32) -> u32;
490
491 #[link_name = "api_key_pressed"]
492 fn _api_key_pressed(key: u32) -> u32;
493
494 #[link_name = "api_scroll_delta"]
495 fn _api_scroll_delta() -> u64;
496
497 #[link_name = "api_modifiers"]
498 fn _api_modifiers() -> u32;
499
500 #[link_name = "api_ui_button"]
503 fn _api_ui_button(
504 id: u32,
505 x: f32,
506 y: f32,
507 w: f32,
508 h: f32,
509 label_ptr: u32,
510 label_len: u32,
511 ) -> u32;
512
513 #[link_name = "api_ui_checkbox"]
514 fn _api_ui_checkbox(
515 id: u32,
516 x: f32,
517 y: f32,
518 label_ptr: u32,
519 label_len: u32,
520 initial: u32,
521 ) -> u32;
522
523 #[link_name = "api_ui_slider"]
524 fn _api_ui_slider(id: u32, x: f32, y: f32, w: f32, min: f32, max: f32, initial: f32) -> f32;
525
526 #[link_name = "api_ui_text_input"]
527 fn _api_ui_text_input(
528 id: u32,
529 x: f32,
530 y: f32,
531 w: f32,
532 init_ptr: u32,
533 init_len: u32,
534 out_ptr: u32,
535 out_cap: u32,
536 ) -> u32;
537
538 #[link_name = "api_audio_play"]
541 fn _api_audio_play(data_ptr: u32, data_len: u32) -> i32;
542
543 #[link_name = "api_audio_play_url"]
544 fn _api_audio_play_url(url_ptr: u32, url_len: u32) -> i32;
545
546 #[link_name = "api_audio_detect_format"]
547 fn _api_audio_detect_format(data_ptr: u32, data_len: u32) -> u32;
548
549 #[link_name = "api_audio_play_with_format"]
550 fn _api_audio_play_with_format(data_ptr: u32, data_len: u32, format_hint: u32) -> i32;
551
552 #[link_name = "api_audio_last_url_content_type"]
553 fn _api_audio_last_url_content_type(out_ptr: u32, out_cap: u32) -> u32;
554
555 #[link_name = "api_audio_pause"]
556 fn _api_audio_pause();
557
558 #[link_name = "api_audio_resume"]
559 fn _api_audio_resume();
560
561 #[link_name = "api_audio_stop"]
562 fn _api_audio_stop();
563
564 #[link_name = "api_audio_set_volume"]
565 fn _api_audio_set_volume(level: f32);
566
567 #[link_name = "api_audio_get_volume"]
568 fn _api_audio_get_volume() -> f32;
569
570 #[link_name = "api_audio_is_playing"]
571 fn _api_audio_is_playing() -> u32;
572
573 #[link_name = "api_audio_position"]
574 fn _api_audio_position() -> u64;
575
576 #[link_name = "api_audio_seek"]
577 fn _api_audio_seek(position_ms: u64) -> i32;
578
579 #[link_name = "api_audio_duration"]
580 fn _api_audio_duration() -> u64;
581
582 #[link_name = "api_audio_set_loop"]
583 fn _api_audio_set_loop(enabled: u32);
584
585 #[link_name = "api_audio_channel_play"]
586 fn _api_audio_channel_play(channel: u32, data_ptr: u32, data_len: u32) -> i32;
587
588 #[link_name = "api_audio_channel_play_with_format"]
589 fn _api_audio_channel_play_with_format(
590 channel: u32,
591 data_ptr: u32,
592 data_len: u32,
593 format_hint: u32,
594 ) -> i32;
595
596 #[link_name = "api_audio_channel_stop"]
597 fn _api_audio_channel_stop(channel: u32);
598
599 #[link_name = "api_audio_channel_set_volume"]
600 fn _api_audio_channel_set_volume(channel: u32, level: f32);
601
602 #[link_name = "api_video_detect_format"]
605 fn _api_video_detect_format(data_ptr: u32, data_len: u32) -> u32;
606
607 #[link_name = "api_video_load"]
608 fn _api_video_load(data_ptr: u32, data_len: u32, format_hint: u32) -> i32;
609
610 #[link_name = "api_video_load_url"]
611 fn _api_video_load_url(url_ptr: u32, url_len: u32) -> i32;
612
613 #[link_name = "api_video_last_url_content_type"]
614 fn _api_video_last_url_content_type(out_ptr: u32, out_cap: u32) -> u32;
615
616 #[link_name = "api_video_hls_variant_count"]
617 fn _api_video_hls_variant_count() -> u32;
618
619 #[link_name = "api_video_hls_variant_url"]
620 fn _api_video_hls_variant_url(index: u32, out_ptr: u32, out_cap: u32) -> u32;
621
622 #[link_name = "api_video_hls_open_variant"]
623 fn _api_video_hls_open_variant(index: u32) -> i32;
624
625 #[link_name = "api_video_play"]
626 fn _api_video_play();
627
628 #[link_name = "api_video_pause"]
629 fn _api_video_pause();
630
631 #[link_name = "api_video_stop"]
632 fn _api_video_stop();
633
634 #[link_name = "api_video_seek"]
635 fn _api_video_seek(position_ms: u64) -> i32;
636
637 #[link_name = "api_video_position"]
638 fn _api_video_position() -> u64;
639
640 #[link_name = "api_video_duration"]
641 fn _api_video_duration() -> u64;
642
643 #[link_name = "api_video_render"]
644 fn _api_video_render(x: f32, y: f32, w: f32, h: f32) -> i32;
645
646 #[link_name = "api_video_set_volume"]
647 fn _api_video_set_volume(level: f32);
648
649 #[link_name = "api_video_get_volume"]
650 fn _api_video_get_volume() -> f32;
651
652 #[link_name = "api_video_set_loop"]
653 fn _api_video_set_loop(enabled: u32);
654
655 #[link_name = "api_video_set_pip"]
656 fn _api_video_set_pip(enabled: u32);
657
658 #[link_name = "api_subtitle_load_srt"]
659 fn _api_subtitle_load_srt(ptr: u32, len: u32) -> i32;
660
661 #[link_name = "api_subtitle_load_vtt"]
662 fn _api_subtitle_load_vtt(ptr: u32, len: u32) -> i32;
663
664 #[link_name = "api_subtitle_clear"]
665 fn _api_subtitle_clear();
666
667 #[link_name = "api_camera_open"]
670 fn _api_camera_open() -> i32;
671
672 #[link_name = "api_camera_close"]
673 fn _api_camera_close();
674
675 #[link_name = "api_camera_capture_frame"]
676 fn _api_camera_capture_frame(out_ptr: u32, out_cap: u32) -> u32;
677
678 #[link_name = "api_camera_frame_dimensions"]
679 fn _api_camera_frame_dimensions() -> u64;
680
681 #[link_name = "api_microphone_open"]
682 fn _api_microphone_open() -> i32;
683
684 #[link_name = "api_microphone_close"]
685 fn _api_microphone_close();
686
687 #[link_name = "api_microphone_sample_rate"]
688 fn _api_microphone_sample_rate() -> u32;
689
690 #[link_name = "api_microphone_read_samples"]
691 fn _api_microphone_read_samples(out_ptr: u32, max_samples: u32) -> u32;
692
693 #[link_name = "api_screen_capture"]
694 fn _api_screen_capture(out_ptr: u32, out_cap: u32) -> i32;
695
696 #[link_name = "api_screen_capture_dimensions"]
697 fn _api_screen_capture_dimensions() -> u64;
698
699 #[link_name = "api_media_pipeline_stats"]
700 fn _api_media_pipeline_stats() -> u64;
701
702 #[link_name = "api_gpu_create_buffer"]
705 fn _api_gpu_create_buffer(size_lo: u32, size_hi: u32, usage: u32) -> u32;
706
707 #[link_name = "api_gpu_create_texture"]
708 fn _api_gpu_create_texture(width: u32, height: u32) -> u32;
709
710 #[link_name = "api_gpu_create_shader"]
711 fn _api_gpu_create_shader(src_ptr: u32, src_len: u32) -> u32;
712
713 #[link_name = "api_gpu_create_render_pipeline"]
714 fn _api_gpu_create_render_pipeline(
715 shader: u32,
716 vs_ptr: u32,
717 vs_len: u32,
718 fs_ptr: u32,
719 fs_len: u32,
720 ) -> u32;
721
722 #[link_name = "api_gpu_create_compute_pipeline"]
723 fn _api_gpu_create_compute_pipeline(shader: u32, ep_ptr: u32, ep_len: u32) -> u32;
724
725 #[link_name = "api_gpu_write_buffer"]
726 fn _api_gpu_write_buffer(
727 handle: u32,
728 offset_lo: u32,
729 offset_hi: u32,
730 data_ptr: u32,
731 data_len: u32,
732 ) -> u32;
733
734 #[link_name = "api_gpu_draw"]
735 fn _api_gpu_draw(pipeline: u32, target: u32, vertex_count: u32, instance_count: u32) -> u32;
736
737 #[link_name = "api_gpu_dispatch_compute"]
738 fn _api_gpu_dispatch_compute(pipeline: u32, x: u32, y: u32, z: u32) -> u32;
739
740 #[link_name = "api_gpu_destroy_buffer"]
741 fn _api_gpu_destroy_buffer(handle: u32) -> u32;
742
743 #[link_name = "api_gpu_destroy_texture"]
744 fn _api_gpu_destroy_texture(handle: u32) -> u32;
745
746 #[link_name = "api_rtc_create_peer"]
749 fn _api_rtc_create_peer(stun_ptr: u32, stun_len: u32) -> u32;
750
751 #[link_name = "api_rtc_close_peer"]
752 fn _api_rtc_close_peer(peer_id: u32) -> u32;
753
754 #[link_name = "api_rtc_create_offer"]
755 fn _api_rtc_create_offer(peer_id: u32, out_ptr: u32, out_cap: u32) -> i32;
756
757 #[link_name = "api_rtc_create_answer"]
758 fn _api_rtc_create_answer(peer_id: u32, out_ptr: u32, out_cap: u32) -> i32;
759
760 #[link_name = "api_rtc_set_local_description"]
761 fn _api_rtc_set_local_description(
762 peer_id: u32,
763 sdp_ptr: u32,
764 sdp_len: u32,
765 is_offer: u32,
766 ) -> i32;
767
768 #[link_name = "api_rtc_set_remote_description"]
769 fn _api_rtc_set_remote_description(
770 peer_id: u32,
771 sdp_ptr: u32,
772 sdp_len: u32,
773 is_offer: u32,
774 ) -> i32;
775
776 #[link_name = "api_rtc_add_ice_candidate"]
777 fn _api_rtc_add_ice_candidate(peer_id: u32, cand_ptr: u32, cand_len: u32) -> i32;
778
779 #[link_name = "api_rtc_connection_state"]
780 fn _api_rtc_connection_state(peer_id: u32) -> u32;
781
782 #[link_name = "api_rtc_poll_ice_candidate"]
783 fn _api_rtc_poll_ice_candidate(peer_id: u32, out_ptr: u32, out_cap: u32) -> i32;
784
785 #[link_name = "api_rtc_create_data_channel"]
786 fn _api_rtc_create_data_channel(
787 peer_id: u32,
788 label_ptr: u32,
789 label_len: u32,
790 ordered: u32,
791 ) -> u32;
792
793 #[link_name = "api_rtc_send"]
794 fn _api_rtc_send(
795 peer_id: u32,
796 channel_id: u32,
797 data_ptr: u32,
798 data_len: u32,
799 is_binary: u32,
800 ) -> i32;
801
802 #[link_name = "api_rtc_recv"]
803 fn _api_rtc_recv(peer_id: u32, channel_id: u32, out_ptr: u32, out_cap: u32) -> i64;
804
805 #[link_name = "api_rtc_poll_data_channel"]
806 fn _api_rtc_poll_data_channel(peer_id: u32, out_ptr: u32, out_cap: u32) -> i32;
807
808 #[link_name = "api_rtc_add_track"]
809 fn _api_rtc_add_track(peer_id: u32, kind: u32) -> u32;
810
811 #[link_name = "api_rtc_poll_track"]
812 fn _api_rtc_poll_track(peer_id: u32, out_ptr: u32, out_cap: u32) -> i32;
813
814 #[link_name = "api_rtc_signal_connect"]
815 fn _api_rtc_signal_connect(url_ptr: u32, url_len: u32) -> u32;
816
817 #[link_name = "api_rtc_signal_join_room"]
818 fn _api_rtc_signal_join_room(room_ptr: u32, room_len: u32) -> i32;
819
820 #[link_name = "api_rtc_signal_send"]
821 fn _api_rtc_signal_send(data_ptr: u32, data_len: u32) -> i32;
822
823 #[link_name = "api_rtc_signal_recv"]
824 fn _api_rtc_signal_recv(out_ptr: u32, out_cap: u32) -> i32;
825
826 #[link_name = "api_ws_connect"]
829 fn _api_ws_connect(url_ptr: u32, url_len: u32) -> u32;
830
831 #[link_name = "api_ws_send_text"]
832 fn _api_ws_send_text(id: u32, data_ptr: u32, data_len: u32) -> i32;
833
834 #[link_name = "api_ws_send_binary"]
835 fn _api_ws_send_binary(id: u32, data_ptr: u32, data_len: u32) -> i32;
836
837 #[link_name = "api_ws_recv"]
838 fn _api_ws_recv(id: u32, out_ptr: u32, out_cap: u32) -> i64;
839
840 #[link_name = "api_ws_ready_state"]
841 fn _api_ws_ready_state(id: u32) -> u32;
842
843 #[link_name = "api_ws_close"]
844 fn _api_ws_close(id: u32) -> i32;
845
846 #[link_name = "api_ws_remove"]
847 fn _api_ws_remove(id: u32);
848
849 #[link_name = "api_midi_input_count"]
852 fn _api_midi_input_count() -> u32;
853
854 #[link_name = "api_midi_output_count"]
855 fn _api_midi_output_count() -> u32;
856
857 #[link_name = "api_midi_input_name"]
858 fn _api_midi_input_name(index: u32, out_ptr: u32, out_cap: u32) -> u32;
859
860 #[link_name = "api_midi_output_name"]
861 fn _api_midi_output_name(index: u32, out_ptr: u32, out_cap: u32) -> u32;
862
863 #[link_name = "api_midi_open_input"]
864 fn _api_midi_open_input(index: u32) -> u32;
865
866 #[link_name = "api_midi_open_output"]
867 fn _api_midi_open_output(index: u32) -> u32;
868
869 #[link_name = "api_midi_send"]
870 fn _api_midi_send(handle: u32, data_ptr: u32, data_len: u32) -> i32;
871
872 #[link_name = "api_midi_recv"]
873 fn _api_midi_recv(handle: u32, out_ptr: u32, out_cap: u32) -> i32;
874
875 #[link_name = "api_midi_close"]
876 fn _api_midi_close(handle: u32);
877
878 #[link_name = "api_url_resolve"]
881 fn _api_url_resolve(
882 base_ptr: u32,
883 base_len: u32,
884 rel_ptr: u32,
885 rel_len: u32,
886 out_ptr: u32,
887 out_cap: u32,
888 ) -> i32;
889
890 #[link_name = "api_url_encode"]
891 fn _api_url_encode(input_ptr: u32, input_len: u32, out_ptr: u32, out_cap: u32) -> u32;
892
893 #[link_name = "api_url_decode"]
894 fn _api_url_decode(input_ptr: u32, input_len: u32, out_ptr: u32, out_cap: u32) -> u32;
895}
896
897pub fn log(msg: &str) {
901 unsafe { _api_log(msg.as_ptr() as u32, msg.len() as u32) }
902}
903
904pub fn warn(msg: &str) {
906 unsafe { _api_warn(msg.as_ptr() as u32, msg.len() as u32) }
907}
908
909pub fn error(msg: &str) {
911 unsafe { _api_error(msg.as_ptr() as u32, msg.len() as u32) }
912}
913
914pub fn get_location() -> String {
918 let mut buf = [0u8; 128];
919 let len = unsafe { _api_get_location(buf.as_mut_ptr() as u32, buf.len() as u32) };
920 String::from_utf8_lossy(&buf[..len as usize]).to_string()
921}
922
923pub struct UploadedFile {
927 pub name: String,
928 pub data: Vec<u8>,
929}
930
931pub fn upload_file() -> Option<UploadedFile> {
934 let mut name_buf = [0u8; 256];
935 let mut data_buf = vec![0u8; 1024 * 1024]; let result = unsafe {
938 _api_upload_file(
939 name_buf.as_mut_ptr() as u32,
940 name_buf.len() as u32,
941 data_buf.as_mut_ptr() as u32,
942 data_buf.len() as u32,
943 )
944 };
945
946 if result == 0 {
947 return None;
948 }
949
950 let name_len = (result >> 32) as usize;
951 let data_len = (result & 0xFFFF_FFFF) as usize;
952
953 Some(UploadedFile {
954 name: String::from_utf8_lossy(&name_buf[..name_len]).to_string(),
955 data: data_buf[..data_len].to_vec(),
956 })
957}
958
959pub struct FileMetadata {
968 pub name: String,
969 pub size: u64,
970 pub mime: String,
971 pub modified_ms: u64,
972 pub is_dir: bool,
973}
974
975pub struct FolderEntry {
977 pub name: String,
978 pub size: u64,
979 pub is_dir: bool,
980 pub handle: u32,
981}
982
983pub fn file_pick(title: &str, filters: &str, multiple: bool) -> Vec<u32> {
989 let mut buf = [0u32; 64];
990 let n = unsafe {
991 _api_file_pick(
992 title.as_ptr() as u32,
993 title.len() as u32,
994 filters.as_ptr() as u32,
995 filters.len() as u32,
996 if multiple { 1 } else { 0 },
997 buf.as_mut_ptr() as u32,
998 (buf.len() * 4) as u32,
999 )
1000 };
1001 if n <= 0 {
1002 return Vec::new();
1003 }
1004 buf[..n as usize].to_vec()
1005}
1006
1007pub fn folder_pick(title: &str) -> Option<u32> {
1012 let h = unsafe { _api_folder_pick(title.as_ptr() as u32, title.len() as u32) };
1013 if h == 0 {
1014 None
1015 } else {
1016 Some(h)
1017 }
1018}
1019
1020fn read_json_len(handle: u32, call: impl Fn(u32, u32, u32) -> i32) -> Option<Vec<u8>> {
1021 let mut buf = vec![0u8; 8 * 1024];
1022 let n = call(handle, buf.as_mut_ptr() as u32, buf.len() as u32);
1023 if n >= 0 {
1024 buf.truncate(n as usize);
1025 return Some(buf);
1026 }
1027 if n < -1 {
1029 let required = (-n) as usize;
1030 let mut big = vec![0u8; required];
1031 let n2 = call(handle, big.as_mut_ptr() as u32, big.len() as u32);
1032 if n2 >= 0 {
1033 big.truncate(n2 as usize);
1034 return Some(big);
1035 }
1036 }
1037 None
1038}
1039
1040pub fn folder_entries(handle: u32) -> Vec<FolderEntry> {
1046 let bytes = match read_json_len(handle, |h, p, c| unsafe { _api_folder_entries(h, p, c) }) {
1047 Some(b) => b,
1048 None => return Vec::new(),
1049 };
1050 parse_folder_entries(&bytes)
1051}
1052
1053fn parse_folder_entries(bytes: &[u8]) -> Vec<FolderEntry> {
1054 let s = core::str::from_utf8(bytes).unwrap_or("");
1057 let mut out = Vec::new();
1058 let mut rest = s.trim();
1059 if !rest.starts_with('[') {
1060 return out;
1061 }
1062 rest = &rest[1..];
1063 loop {
1064 rest = rest.trim_start_matches(|c: char| c.is_whitespace() || c == ',');
1065 if rest.starts_with(']') || rest.is_empty() {
1066 break;
1067 }
1068 let Some(end) = rest.find('}') else { break };
1069 let obj = &rest[..=end];
1070 rest = &rest[end + 1..];
1071 let name = json_str_field(obj, "\"name\":").unwrap_or_default();
1072 let size = json_num_field(obj, "\"size\":").unwrap_or(0);
1073 let is_dir = json_bool_field(obj, "\"is_dir\":").unwrap_or(false);
1074 let handle = json_num_field(obj, "\"handle\":").unwrap_or(0) as u32;
1075 out.push(FolderEntry {
1076 name,
1077 size,
1078 is_dir,
1079 handle,
1080 });
1081 }
1082 out
1083}
1084
1085fn json_str_field(obj: &str, key: &str) -> Option<String> {
1086 let idx = obj.find(key)?;
1087 let after = &obj[idx + key.len()..];
1088 let start = after.find('"')? + 1;
1089 let mut out = String::new();
1090 let bytes = after.as_bytes();
1091 let mut i = start;
1092 while i < bytes.len() {
1093 let c = bytes[i];
1094 if c == b'\\' && i + 1 < bytes.len() {
1095 match bytes[i + 1] {
1096 b'"' => out.push('"'),
1097 b'\\' => out.push('\\'),
1098 b'n' => out.push('\n'),
1099 b'r' => out.push('\r'),
1100 b't' => out.push('\t'),
1101 _ => out.push(bytes[i + 1] as char),
1102 }
1103 i += 2;
1104 } else if c == b'"' {
1105 return Some(out);
1106 } else {
1107 out.push(c as char);
1108 i += 1;
1109 }
1110 }
1111 None
1112}
1113
1114fn json_num_field(obj: &str, key: &str) -> Option<u64> {
1115 let idx = obj.find(key)?;
1116 let after = obj[idx + key.len()..].trim_start();
1117 let end = after
1118 .find(|c: char| !c.is_ascii_digit())
1119 .unwrap_or(after.len());
1120 after[..end].parse().ok()
1121}
1122
1123fn json_bool_field(obj: &str, key: &str) -> Option<bool> {
1124 let idx = obj.find(key)?;
1125 let after = obj[idx + key.len()..].trim_start();
1126 if after.starts_with("true") {
1127 Some(true)
1128 } else if after.starts_with("false") {
1129 Some(false)
1130 } else {
1131 None
1132 }
1133}
1134
1135pub fn file_read(handle: u32) -> Option<Vec<u8>> {
1140 let mut buf = vec![0u8; 64 * 1024];
1141 let n = unsafe { _api_file_read(handle, buf.as_mut_ptr() as u32, buf.len() as u32) };
1142 if n >= 0 {
1143 buf.truncate(n as usize);
1144 return Some(buf);
1145 }
1146 if n < -1 {
1147 let required = (-n) as usize;
1148 if required > 64 * 1024 * 1024 {
1149 return None;
1150 }
1151 let mut big = vec![0u8; required];
1152 let n2 = unsafe { _api_file_read(handle, big.as_mut_ptr() as u32, big.len() as u32) };
1153 if n2 >= 0 {
1154 big.truncate(n2 as usize);
1155 return Some(big);
1156 }
1157 }
1158 None
1159}
1160
1161pub fn file_read_range(handle: u32, offset: u64, len: u32) -> Option<Vec<u8>> {
1166 let mut buf = vec![0u8; len as usize];
1167 let n = unsafe {
1168 _api_file_read_range(
1169 handle,
1170 offset as u32,
1171 (offset >> 32) as u32,
1172 len,
1173 buf.as_mut_ptr() as u32,
1174 buf.len() as u32,
1175 )
1176 };
1177 if n < 0 {
1178 return None;
1179 }
1180 buf.truncate(n as usize);
1181 Some(buf)
1182}
1183
1184pub fn file_metadata(handle: u32) -> Option<FileMetadata> {
1186 let bytes = read_json_len(handle, |h, p, c| unsafe { _api_file_metadata(h, p, c) })?;
1187 let s = core::str::from_utf8(&bytes).ok()?;
1188 Some(FileMetadata {
1189 name: json_str_field(s, "\"name\":").unwrap_or_default(),
1190 size: json_num_field(s, "\"size\":").unwrap_or(0),
1191 mime: json_str_field(s, "\"mime\":").unwrap_or_default(),
1192 modified_ms: json_num_field(s, "\"modified_ms\":").unwrap_or(0),
1193 is_dir: json_bool_field(s, "\"is_dir\":").unwrap_or(false),
1194 })
1195}
1196
1197pub fn canvas_clear(r: u8, g: u8, b: u8, a: u8) {
1201 unsafe { _api_canvas_clear(r as u32, g as u32, b as u32, a as u32) }
1202}
1203
1204pub fn canvas_rect(x: f32, y: f32, w: f32, h: f32, r: u8, g: u8, b: u8, a: u8) {
1206 unsafe { _api_canvas_rect(x, y, w, h, r as u32, g as u32, b as u32, a as u32) }
1207}
1208
1209pub fn canvas_circle(cx: f32, cy: f32, radius: f32, r: u8, g: u8, b: u8, a: u8) {
1211 unsafe { _api_canvas_circle(cx, cy, radius, r as u32, g as u32, b as u32, a as u32) }
1212}
1213
1214pub fn canvas_text(x: f32, y: f32, size: f32, r: u8, g: u8, b: u8, a: u8, text: &str) {
1216 unsafe {
1217 _api_canvas_text(
1218 x,
1219 y,
1220 size,
1221 r as u32,
1222 g as u32,
1223 b as u32,
1224 a as u32,
1225 text.as_ptr() as u32,
1226 text.len() as u32,
1227 )
1228 }
1229}
1230
1231pub fn canvas_line(x1: f32, y1: f32, x2: f32, y2: f32, r: u8, g: u8, b: u8, a: u8, thickness: f32) {
1233 unsafe {
1234 _api_canvas_line(
1235 x1, y1, x2, y2, r as u32, g as u32, b as u32, a as u32, thickness,
1236 )
1237 }
1238}
1239
1240pub fn canvas_dimensions() -> (u32, u32) {
1242 let packed = unsafe { _api_canvas_dimensions() };
1243 ((packed >> 32) as u32, (packed & 0xFFFF_FFFF) as u32)
1244}
1245
1246pub fn canvas_image(x: f32, y: f32, w: f32, h: f32, data: &[u8]) {
1249 unsafe { _api_canvas_image(x, y, w, h, data.as_ptr() as u32, data.len() as u32) }
1250}
1251
1252pub fn canvas_rounded_rect(
1256 x: f32,
1257 y: f32,
1258 w: f32,
1259 h: f32,
1260 radius: f32,
1261 r: u8,
1262 g: u8,
1263 b: u8,
1264 a: u8,
1265) {
1266 unsafe { _api_canvas_rounded_rect(x, y, w, h, radius, r as u32, g as u32, b as u32, a as u32) }
1267}
1268
1269pub fn canvas_arc(
1271 cx: f32,
1272 cy: f32,
1273 radius: f32,
1274 start_angle: f32,
1275 end_angle: f32,
1276 r: u8,
1277 g: u8,
1278 b: u8,
1279 a: u8,
1280 thickness: f32,
1281) {
1282 unsafe {
1283 _api_canvas_arc(
1284 cx,
1285 cy,
1286 radius,
1287 start_angle,
1288 end_angle,
1289 r as u32,
1290 g as u32,
1291 b as u32,
1292 a as u32,
1293 thickness,
1294 )
1295 }
1296}
1297
1298pub fn canvas_bezier(
1300 x1: f32,
1301 y1: f32,
1302 cp1x: f32,
1303 cp1y: f32,
1304 cp2x: f32,
1305 cp2y: f32,
1306 x2: f32,
1307 y2: f32,
1308 r: u8,
1309 g: u8,
1310 b: u8,
1311 a: u8,
1312 thickness: f32,
1313) {
1314 unsafe {
1315 _api_canvas_bezier(
1316 x1, y1, cp1x, cp1y, cp2x, cp2y, x2, y2, r as u32, g as u32, b as u32, a as u32,
1317 thickness,
1318 )
1319 }
1320}
1321
1322pub const GRADIENT_LINEAR: u32 = 0;
1324pub const GRADIENT_RADIAL: u32 = 1;
1325
1326pub fn canvas_gradient(
1333 x: f32,
1334 y: f32,
1335 w: f32,
1336 h: f32,
1337 kind: u32,
1338 ax: f32,
1339 ay: f32,
1340 bx: f32,
1341 by: f32,
1342 stops: &[(f32, u8, u8, u8, u8)],
1343) {
1344 let mut buf = Vec::with_capacity(stops.len() * 8);
1345 for &(offset, r, g, b, a) in stops {
1346 buf.extend_from_slice(&offset.to_le_bytes());
1347 buf.push(r);
1348 buf.push(g);
1349 buf.push(b);
1350 buf.push(a);
1351 }
1352 unsafe {
1353 _api_canvas_gradient(
1354 x,
1355 y,
1356 w,
1357 h,
1358 kind,
1359 ax,
1360 ay,
1361 bx,
1362 by,
1363 buf.as_ptr() as u32,
1364 buf.len() as u32,
1365 )
1366 }
1367}
1368
1369pub fn canvas_save() {
1374 unsafe { _api_canvas_save() }
1375}
1376
1377pub fn canvas_restore() {
1379 unsafe { _api_canvas_restore() }
1380}
1381
1382pub fn canvas_transform(a: f32, b: f32, c: f32, d: f32, tx: f32, ty: f32) {
1393 unsafe { _api_canvas_transform(a, b, c, d, tx, ty) }
1394}
1395
1396pub fn canvas_clip(x: f32, y: f32, w: f32, h: f32) {
1399 unsafe { _api_canvas_clip(x, y, w, h) }
1400}
1401
1402pub fn canvas_opacity(alpha: f32) {
1405 unsafe { _api_canvas_opacity(alpha) }
1406}
1407
1408pub mod gpu_usage {
1412 pub const VERTEX: u32 = 0x0020;
1413 pub const INDEX: u32 = 0x0010;
1414 pub const UNIFORM: u32 = 0x0040;
1415 pub const STORAGE: u32 = 0x0080;
1416}
1417
1418pub fn gpu_create_buffer(size: u64, usage: u32) -> u32 {
1422 unsafe { _api_gpu_create_buffer(size as u32, (size >> 32) as u32, usage) }
1423}
1424
1425pub fn gpu_create_texture(width: u32, height: u32) -> u32 {
1427 unsafe { _api_gpu_create_texture(width, height) }
1428}
1429
1430pub fn gpu_create_shader(source: &str) -> u32 {
1432 unsafe { _api_gpu_create_shader(source.as_ptr() as u32, source.len() as u32) }
1433}
1434
1435pub fn gpu_create_pipeline(shader: u32, vertex_entry: &str, fragment_entry: &str) -> u32 {
1439 unsafe {
1440 _api_gpu_create_render_pipeline(
1441 shader,
1442 vertex_entry.as_ptr() as u32,
1443 vertex_entry.len() as u32,
1444 fragment_entry.as_ptr() as u32,
1445 fragment_entry.len() as u32,
1446 )
1447 }
1448}
1449
1450pub fn gpu_create_compute_pipeline(shader: u32, entry_point: &str) -> u32 {
1452 unsafe {
1453 _api_gpu_create_compute_pipeline(
1454 shader,
1455 entry_point.as_ptr() as u32,
1456 entry_point.len() as u32,
1457 )
1458 }
1459}
1460
1461pub fn gpu_write_buffer(handle: u32, offset: u64, data: &[u8]) -> bool {
1463 unsafe {
1464 _api_gpu_write_buffer(
1465 handle,
1466 offset as u32,
1467 (offset >> 32) as u32,
1468 data.as_ptr() as u32,
1469 data.len() as u32,
1470 ) != 0
1471 }
1472}
1473
1474pub fn gpu_draw(
1476 pipeline: u32,
1477 target_texture: u32,
1478 vertex_count: u32,
1479 instance_count: u32,
1480) -> bool {
1481 unsafe { _api_gpu_draw(pipeline, target_texture, vertex_count, instance_count) != 0 }
1482}
1483
1484pub fn gpu_dispatch_compute(pipeline: u32, x: u32, y: u32, z: u32) -> bool {
1486 unsafe { _api_gpu_dispatch_compute(pipeline, x, y, z) != 0 }
1487}
1488
1489pub fn gpu_destroy_buffer(handle: u32) -> bool {
1491 unsafe { _api_gpu_destroy_buffer(handle) != 0 }
1492}
1493
1494pub fn gpu_destroy_texture(handle: u32) -> bool {
1496 unsafe { _api_gpu_destroy_texture(handle) != 0 }
1497}
1498
1499pub fn storage_set(key: &str, value: &str) {
1503 unsafe {
1504 _api_storage_set(
1505 key.as_ptr() as u32,
1506 key.len() as u32,
1507 value.as_ptr() as u32,
1508 value.len() as u32,
1509 )
1510 }
1511}
1512
1513pub fn storage_get(key: &str) -> String {
1515 let mut buf = [0u8; 4096];
1516 let len = unsafe {
1517 _api_storage_get(
1518 key.as_ptr() as u32,
1519 key.len() as u32,
1520 buf.as_mut_ptr() as u32,
1521 buf.len() as u32,
1522 )
1523 };
1524 String::from_utf8_lossy(&buf[..len as usize]).to_string()
1525}
1526
1527pub fn storage_remove(key: &str) {
1529 unsafe { _api_storage_remove(key.as_ptr() as u32, key.len() as u32) }
1530}
1531
1532pub fn clipboard_write(text: &str) {
1536 unsafe { _api_clipboard_write(text.as_ptr() as u32, text.len() as u32) }
1537}
1538
1539pub fn clipboard_read() -> String {
1541 let mut buf = [0u8; 4096];
1542 let len = unsafe { _api_clipboard_read(buf.as_mut_ptr() as u32, buf.len() as u32) };
1543 String::from_utf8_lossy(&buf[..len as usize]).to_string()
1544}
1545
1546pub fn time_now_ms() -> u64 {
1550 unsafe { _api_time_now_ms() }
1551}
1552
1553pub fn set_timeout(callback_id: u32, delay_ms: u32) -> u32 {
1557 unsafe { _api_set_timeout(callback_id, delay_ms) }
1558}
1559
1560pub fn set_interval(callback_id: u32, interval_ms: u32) -> u32 {
1564 unsafe { _api_set_interval(callback_id, interval_ms) }
1565}
1566
1567pub fn clear_timer(timer_id: u32) {
1569 unsafe { _api_clear_timer(timer_id) }
1570}
1571
1572pub fn request_animation_frame(callback_id: u32) -> u32 {
1578 unsafe { _api_request_animation_frame(callback_id) }
1579}
1580
1581pub fn cancel_animation_frame(request_id: u32) {
1583 unsafe { _api_cancel_animation_frame(request_id) }
1584}
1585
1586pub fn on_event(event_type: &str, callback_id: u32) -> u32 {
1617 unsafe {
1618 _api_on_event(
1619 event_type.as_ptr() as u32,
1620 event_type.len() as u32,
1621 callback_id,
1622 )
1623 }
1624}
1625
1626pub fn off_event(listener_id: u32) -> bool {
1629 unsafe { _api_off_event(listener_id) != 0 }
1630}
1631
1632pub fn emit_event(event_type: &str, data: &[u8]) {
1636 unsafe {
1637 _api_emit_event(
1638 event_type.as_ptr() as u32,
1639 event_type.len() as u32,
1640 data.as_ptr() as u32,
1641 data.len() as u32,
1642 )
1643 }
1644}
1645
1646pub fn event_type() -> String {
1649 let len = unsafe { _api_event_type_len() } as usize;
1650 if len == 0 {
1651 return String::new();
1652 }
1653 let mut buf = vec![0u8; len];
1654 let written = unsafe { _api_event_type_read(buf.as_mut_ptr() as u32, len as u32) } as usize;
1655 buf.truncate(written);
1656 String::from_utf8_lossy(&buf).into_owned()
1657}
1658
1659pub fn event_data(out: &mut [u8]) -> usize {
1662 let cap = out.len() as u32;
1663 if cap == 0 {
1664 return 0;
1665 }
1666 unsafe { _api_event_data_read(out.as_mut_ptr() as u32, cap) as usize }
1667}
1668
1669pub fn event_data_into() -> Vec<u8> {
1671 let len = unsafe { _api_event_data_len() } as usize;
1672 if len == 0 {
1673 return Vec::new();
1674 }
1675 let mut buf = vec![0u8; len];
1676 let written = unsafe { _api_event_data_read(buf.as_mut_ptr() as u32, len as u32) } as usize;
1677 buf.truncate(written);
1678 buf
1679}
1680
1681pub fn random_u64() -> u64 {
1685 unsafe { _api_random() }
1686}
1687
1688pub fn random_f64() -> f64 {
1690 (random_u64() >> 11) as f64 / (1u64 << 53) as f64
1691}
1692
1693pub fn notify(title: &str, body: &str) {
1697 unsafe {
1698 _api_notify(
1699 title.as_ptr() as u32,
1700 title.len() as u32,
1701 body.as_ptr() as u32,
1702 body.len() as u32,
1703 )
1704 }
1705}
1706
1707#[repr(u32)]
1711#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1712pub enum AudioFormat {
1713 Unknown = 0,
1715 Wav = 1,
1716 Mp3 = 2,
1717 Ogg = 3,
1718 Flac = 4,
1719}
1720
1721impl From<u32> for AudioFormat {
1722 fn from(code: u32) -> Self {
1723 match code {
1724 1 => AudioFormat::Wav,
1725 2 => AudioFormat::Mp3,
1726 3 => AudioFormat::Ogg,
1727 4 => AudioFormat::Flac,
1728 _ => AudioFormat::Unknown,
1729 }
1730 }
1731}
1732
1733impl From<AudioFormat> for u32 {
1734 fn from(f: AudioFormat) -> u32 {
1735 f as u32
1736 }
1737}
1738
1739pub fn audio_play(data: &[u8]) -> i32 {
1742 unsafe { _api_audio_play(data.as_ptr() as u32, data.len() as u32) }
1743}
1744
1745pub fn audio_detect_format(data: &[u8]) -> AudioFormat {
1747 let code = unsafe { _api_audio_detect_format(data.as_ptr() as u32, data.len() as u32) };
1748 AudioFormat::from(code)
1749}
1750
1751pub fn audio_play_with_format(data: &[u8], format: AudioFormat) -> i32 {
1754 unsafe {
1755 _api_audio_play_with_format(data.as_ptr() as u32, data.len() as u32, u32::from(format))
1756 }
1757}
1758
1759pub fn audio_play_url(url: &str) -> i32 {
1764 unsafe { _api_audio_play_url(url.as_ptr() as u32, url.len() as u32) }
1765}
1766
1767pub fn audio_last_url_content_type() -> String {
1769 let mut buf = [0u8; 512];
1770 let len =
1771 unsafe { _api_audio_last_url_content_type(buf.as_mut_ptr() as u32, buf.len() as u32) };
1772 let n = (len as usize).min(buf.len());
1773 String::from_utf8_lossy(&buf[..n]).to_string()
1774}
1775
1776pub fn audio_pause() {
1778 unsafe { _api_audio_pause() }
1779}
1780
1781pub fn audio_resume() {
1783 unsafe { _api_audio_resume() }
1784}
1785
1786pub fn audio_stop() {
1788 unsafe { _api_audio_stop() }
1789}
1790
1791pub fn audio_set_volume(level: f32) {
1793 unsafe { _api_audio_set_volume(level) }
1794}
1795
1796pub fn audio_get_volume() -> f32 {
1798 unsafe { _api_audio_get_volume() }
1799}
1800
1801pub fn audio_is_playing() -> bool {
1803 unsafe { _api_audio_is_playing() != 0 }
1804}
1805
1806pub fn audio_position() -> u64 {
1808 unsafe { _api_audio_position() }
1809}
1810
1811pub fn audio_seek(position_ms: u64) -> i32 {
1813 unsafe { _api_audio_seek(position_ms) }
1814}
1815
1816pub fn audio_duration() -> u64 {
1819 unsafe { _api_audio_duration() }
1820}
1821
1822pub fn audio_set_loop(enabled: bool) {
1825 unsafe { _api_audio_set_loop(if enabled { 1 } else { 0 }) }
1826}
1827
1828pub fn audio_channel_play(channel: u32, data: &[u8]) -> i32 {
1834 unsafe { _api_audio_channel_play(channel, data.as_ptr() as u32, data.len() as u32) }
1835}
1836
1837pub fn audio_channel_play_with_format(channel: u32, data: &[u8], format: AudioFormat) -> i32 {
1839 unsafe {
1840 _api_audio_channel_play_with_format(
1841 channel,
1842 data.as_ptr() as u32,
1843 data.len() as u32,
1844 u32::from(format),
1845 )
1846 }
1847}
1848
1849pub fn audio_channel_stop(channel: u32) {
1851 unsafe { _api_audio_channel_stop(channel) }
1852}
1853
1854pub fn audio_channel_set_volume(channel: u32, level: f32) {
1856 unsafe { _api_audio_channel_set_volume(channel, level) }
1857}
1858
1859#[repr(u32)]
1863#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1864pub enum VideoFormat {
1865 Unknown = 0,
1866 Mp4 = 1,
1867 Webm = 2,
1868 Av1 = 3,
1869}
1870
1871impl From<u32> for VideoFormat {
1872 fn from(code: u32) -> Self {
1873 match code {
1874 1 => VideoFormat::Mp4,
1875 2 => VideoFormat::Webm,
1876 3 => VideoFormat::Av1,
1877 _ => VideoFormat::Unknown,
1878 }
1879 }
1880}
1881
1882impl From<VideoFormat> for u32 {
1883 fn from(f: VideoFormat) -> u32 {
1884 f as u32
1885 }
1886}
1887
1888pub fn video_detect_format(data: &[u8]) -> VideoFormat {
1890 let code = unsafe { _api_video_detect_format(data.as_ptr() as u32, data.len() as u32) };
1891 VideoFormat::from(code)
1892}
1893
1894pub fn video_load(data: &[u8]) -> i32 {
1897 unsafe {
1898 _api_video_load(
1899 data.as_ptr() as u32,
1900 data.len() as u32,
1901 VideoFormat::Unknown as u32,
1902 )
1903 }
1904}
1905
1906pub fn video_load_with_format(data: &[u8], format: VideoFormat) -> i32 {
1908 unsafe { _api_video_load(data.as_ptr() as u32, data.len() as u32, u32::from(format)) }
1909}
1910
1911pub fn video_load_url(url: &str) -> i32 {
1913 unsafe { _api_video_load_url(url.as_ptr() as u32, url.len() as u32) }
1914}
1915
1916pub fn video_last_url_content_type() -> String {
1918 let mut buf = [0u8; 512];
1919 let len =
1920 unsafe { _api_video_last_url_content_type(buf.as_mut_ptr() as u32, buf.len() as u32) };
1921 let n = (len as usize).min(buf.len());
1922 String::from_utf8_lossy(&buf[..n]).to_string()
1923}
1924
1925pub fn video_hls_variant_count() -> u32 {
1927 unsafe { _api_video_hls_variant_count() }
1928}
1929
1930pub fn video_hls_variant_url(index: u32) -> String {
1932 let mut buf = [0u8; 2048];
1933 let len =
1934 unsafe { _api_video_hls_variant_url(index, buf.as_mut_ptr() as u32, buf.len() as u32) };
1935 let n = (len as usize).min(buf.len());
1936 String::from_utf8_lossy(&buf[..n]).to_string()
1937}
1938
1939pub fn video_hls_open_variant(index: u32) -> i32 {
1941 unsafe { _api_video_hls_open_variant(index) }
1942}
1943
1944pub fn video_play() {
1945 unsafe { _api_video_play() }
1946}
1947
1948pub fn video_pause() {
1949 unsafe { _api_video_pause() }
1950}
1951
1952pub fn video_stop() {
1953 unsafe { _api_video_stop() }
1954}
1955
1956pub fn video_seek(position_ms: u64) -> i32 {
1957 unsafe { _api_video_seek(position_ms) }
1958}
1959
1960pub fn video_position() -> u64 {
1961 unsafe { _api_video_position() }
1962}
1963
1964pub fn video_duration() -> u64 {
1965 unsafe { _api_video_duration() }
1966}
1967
1968pub fn video_render(x: f32, y: f32, w: f32, h: f32) -> i32 {
1970 unsafe { _api_video_render(x, y, w, h) }
1971}
1972
1973pub fn video_set_volume(level: f32) {
1975 unsafe { _api_video_set_volume(level) }
1976}
1977
1978pub fn video_get_volume() -> f32 {
1979 unsafe { _api_video_get_volume() }
1980}
1981
1982pub fn video_set_loop(enabled: bool) {
1983 unsafe { _api_video_set_loop(if enabled { 1 } else { 0 }) }
1984}
1985
1986pub fn video_set_pip(enabled: bool) {
1988 unsafe { _api_video_set_pip(if enabled { 1 } else { 0 }) }
1989}
1990
1991pub fn subtitle_load_srt(text: &str) -> i32 {
1993 unsafe { _api_subtitle_load_srt(text.as_ptr() as u32, text.len() as u32) }
1994}
1995
1996pub fn subtitle_load_vtt(text: &str) -> i32 {
1998 unsafe { _api_subtitle_load_vtt(text.as_ptr() as u32, text.len() as u32) }
1999}
2000
2001pub fn subtitle_clear() {
2002 unsafe { _api_subtitle_clear() }
2003}
2004
2005pub fn camera_open() -> i32 {
2011 unsafe { _api_camera_open() }
2012}
2013
2014pub fn camera_close() {
2016 unsafe { _api_camera_close() }
2017}
2018
2019pub fn camera_capture_frame(out: &mut [u8]) -> u32 {
2022 unsafe { _api_camera_capture_frame(out.as_mut_ptr() as u32, out.len() as u32) }
2023}
2024
2025pub fn camera_frame_dimensions() -> (u32, u32) {
2027 let packed = unsafe { _api_camera_frame_dimensions() };
2028 let w = (packed >> 32) as u32;
2029 let h = packed as u32;
2030 (w, h)
2031}
2032
2033pub fn microphone_open() -> i32 {
2037 unsafe { _api_microphone_open() }
2038}
2039
2040pub fn microphone_close() {
2041 unsafe { _api_microphone_close() }
2042}
2043
2044pub fn microphone_sample_rate() -> u32 {
2046 unsafe { _api_microphone_sample_rate() }
2047}
2048
2049pub fn microphone_read_samples(out: &mut [f32]) -> u32 {
2052 unsafe { _api_microphone_read_samples(out.as_mut_ptr() as u32, out.len() as u32) }
2053}
2054
2055pub fn screen_capture(out: &mut [u8]) -> Result<usize, i32> {
2059 let n = unsafe { _api_screen_capture(out.as_mut_ptr() as u32, out.len() as u32) };
2060 if n >= 0 {
2061 Ok(n as usize)
2062 } else {
2063 Err(n)
2064 }
2065}
2066
2067pub fn screen_capture_dimensions() -> (u32, u32) {
2069 let packed = unsafe { _api_screen_capture_dimensions() };
2070 let w = (packed >> 32) as u32;
2071 let h = packed as u32;
2072 (w, h)
2073}
2074
2075pub fn media_pipeline_stats() -> (u64, u32) {
2078 let packed = unsafe { _api_media_pipeline_stats() };
2079 let camera_frames = packed >> 32;
2080 let mic_ring = packed as u32;
2081 (camera_frames, mic_ring)
2082}
2083
2084pub const RTC_STATE_NEW: u32 = 0;
2088pub const RTC_STATE_CONNECTING: u32 = 1;
2090pub const RTC_STATE_CONNECTED: u32 = 2;
2092pub const RTC_STATE_DISCONNECTED: u32 = 3;
2094pub const RTC_STATE_FAILED: u32 = 4;
2096pub const RTC_STATE_CLOSED: u32 = 5;
2098
2099pub const RTC_TRACK_AUDIO: u32 = 0;
2101pub const RTC_TRACK_VIDEO: u32 = 1;
2103
2104pub struct RtcMessage {
2106 pub channel_id: u32,
2108 pub is_binary: bool,
2110 pub data: Vec<u8>,
2112}
2113
2114impl RtcMessage {
2115 pub fn text(&self) -> String {
2117 String::from_utf8_lossy(&self.data).to_string()
2118 }
2119}
2120
2121pub struct RtcDataChannelInfo {
2123 pub channel_id: u32,
2125 pub label: String,
2127}
2128
2129pub fn rtc_create_peer(stun_servers: &str) -> u32 {
2136 unsafe { _api_rtc_create_peer(stun_servers.as_ptr() as u32, stun_servers.len() as u32) }
2137}
2138
2139pub fn rtc_close_peer(peer_id: u32) -> bool {
2141 unsafe { _api_rtc_close_peer(peer_id) != 0 }
2142}
2143
2144pub fn rtc_create_offer(peer_id: u32) -> Result<String, i32> {
2148 let mut buf = vec![0u8; 16 * 1024];
2149 let n = unsafe { _api_rtc_create_offer(peer_id, buf.as_mut_ptr() as u32, buf.len() as u32) };
2150 if n < 0 {
2151 Err(n)
2152 } else {
2153 Ok(String::from_utf8_lossy(&buf[..n as usize]).to_string())
2154 }
2155}
2156
2157pub fn rtc_create_answer(peer_id: u32) -> Result<String, i32> {
2159 let mut buf = vec![0u8; 16 * 1024];
2160 let n = unsafe { _api_rtc_create_answer(peer_id, buf.as_mut_ptr() as u32, buf.len() as u32) };
2161 if n < 0 {
2162 Err(n)
2163 } else {
2164 Ok(String::from_utf8_lossy(&buf[..n as usize]).to_string())
2165 }
2166}
2167
2168pub fn rtc_set_local_description(peer_id: u32, sdp: &str, is_offer: bool) -> i32 {
2172 unsafe {
2173 _api_rtc_set_local_description(
2174 peer_id,
2175 sdp.as_ptr() as u32,
2176 sdp.len() as u32,
2177 if is_offer { 1 } else { 0 },
2178 )
2179 }
2180}
2181
2182pub fn rtc_set_remote_description(peer_id: u32, sdp: &str, is_offer: bool) -> i32 {
2184 unsafe {
2185 _api_rtc_set_remote_description(
2186 peer_id,
2187 sdp.as_ptr() as u32,
2188 sdp.len() as u32,
2189 if is_offer { 1 } else { 0 },
2190 )
2191 }
2192}
2193
2194pub fn rtc_add_ice_candidate(peer_id: u32, candidate_json: &str) -> i32 {
2196 unsafe {
2197 _api_rtc_add_ice_candidate(
2198 peer_id,
2199 candidate_json.as_ptr() as u32,
2200 candidate_json.len() as u32,
2201 )
2202 }
2203}
2204
2205pub fn rtc_connection_state(peer_id: u32) -> u32 {
2207 unsafe { _api_rtc_connection_state(peer_id) }
2208}
2209
2210pub fn rtc_poll_ice_candidate(peer_id: u32) -> Option<String> {
2213 let mut buf = vec![0u8; 4096];
2214 let n =
2215 unsafe { _api_rtc_poll_ice_candidate(peer_id, buf.as_mut_ptr() as u32, buf.len() as u32) };
2216 if n <= 0 {
2217 None
2218 } else {
2219 Some(String::from_utf8_lossy(&buf[..n as usize]).to_string())
2220 }
2221}
2222
2223pub fn rtc_create_data_channel(peer_id: u32, label: &str, ordered: bool) -> u32 {
2228 unsafe {
2229 _api_rtc_create_data_channel(
2230 peer_id,
2231 label.as_ptr() as u32,
2232 label.len() as u32,
2233 if ordered { 1 } else { 0 },
2234 )
2235 }
2236}
2237
2238pub fn rtc_send_text(peer_id: u32, channel_id: u32, text: &str) -> i32 {
2240 unsafe {
2241 _api_rtc_send(
2242 peer_id,
2243 channel_id,
2244 text.as_ptr() as u32,
2245 text.len() as u32,
2246 0,
2247 )
2248 }
2249}
2250
2251pub fn rtc_send_binary(peer_id: u32, channel_id: u32, data: &[u8]) -> i32 {
2253 unsafe {
2254 _api_rtc_send(
2255 peer_id,
2256 channel_id,
2257 data.as_ptr() as u32,
2258 data.len() as u32,
2259 1,
2260 )
2261 }
2262}
2263
2264pub fn rtc_send(peer_id: u32, channel_id: u32, data: &[u8], is_binary: bool) -> i32 {
2266 unsafe {
2267 _api_rtc_send(
2268 peer_id,
2269 channel_id,
2270 data.as_ptr() as u32,
2271 data.len() as u32,
2272 if is_binary { 1 } else { 0 },
2273 )
2274 }
2275}
2276
2277pub fn rtc_recv(peer_id: u32, channel_id: u32) -> Option<RtcMessage> {
2282 let mut buf = vec![0u8; 64 * 1024];
2283 let packed = unsafe {
2284 _api_rtc_recv(
2285 peer_id,
2286 channel_id,
2287 buf.as_mut_ptr() as u32,
2288 buf.len() as u32,
2289 )
2290 };
2291 if packed <= 0 {
2292 return None;
2293 }
2294 let packed = packed as u64;
2295 let data_len = (packed & 0xFFFF_FFFF) as usize;
2296 let is_binary = (packed >> 32) & 1 != 0;
2297 let ch = (packed >> 48) as u32;
2298 Some(RtcMessage {
2299 channel_id: ch,
2300 is_binary,
2301 data: buf[..data_len].to_vec(),
2302 })
2303}
2304
2305pub fn rtc_poll_data_channel(peer_id: u32) -> Option<RtcDataChannelInfo> {
2309 let mut buf = vec![0u8; 1024];
2310 let n =
2311 unsafe { _api_rtc_poll_data_channel(peer_id, buf.as_mut_ptr() as u32, buf.len() as u32) };
2312 if n <= 0 {
2313 return None;
2314 }
2315 let info = String::from_utf8_lossy(&buf[..n as usize]).to_string();
2316 let (id_str, label) = info.split_once(':').unwrap_or(("0", ""));
2317 Some(RtcDataChannelInfo {
2318 channel_id: id_str.parse().unwrap_or(0),
2319 label: label.to_string(),
2320 })
2321}
2322
2323pub fn rtc_add_track(peer_id: u32, kind: u32) -> u32 {
2328 unsafe { _api_rtc_add_track(peer_id, kind) }
2329}
2330
2331pub struct RtcTrackInfo {
2333 pub kind: u32,
2335 pub id: String,
2337 pub stream_id: String,
2339}
2340
2341pub fn rtc_poll_track(peer_id: u32) -> Option<RtcTrackInfo> {
2345 let mut buf = vec![0u8; 1024];
2346 let n = unsafe { _api_rtc_poll_track(peer_id, buf.as_mut_ptr() as u32, buf.len() as u32) };
2347 if n <= 0 {
2348 return None;
2349 }
2350 let info = String::from_utf8_lossy(&buf[..n as usize]).to_string();
2351 let mut parts = info.splitn(3, ':');
2352 let kind = parts.next().unwrap_or("2").parse().unwrap_or(2);
2353 let id = parts.next().unwrap_or("").to_string();
2354 let stream_id = parts.next().unwrap_or("").to_string();
2355 Some(RtcTrackInfo {
2356 kind,
2357 id,
2358 stream_id,
2359 })
2360}
2361
2362pub fn rtc_signal_connect(url: &str) -> bool {
2366 unsafe { _api_rtc_signal_connect(url.as_ptr() as u32, url.len() as u32) != 0 }
2367}
2368
2369pub fn rtc_signal_join_room(room: &str) -> i32 {
2371 unsafe { _api_rtc_signal_join_room(room.as_ptr() as u32, room.len() as u32) }
2372}
2373
2374pub fn rtc_signal_send(data: &[u8]) -> i32 {
2376 unsafe { _api_rtc_signal_send(data.as_ptr() as u32, data.len() as u32) }
2377}
2378
2379pub fn rtc_signal_recv() -> Option<Vec<u8>> {
2381 let mut buf = vec![0u8; 16 * 1024];
2382 let n = unsafe { _api_rtc_signal_recv(buf.as_mut_ptr() as u32, buf.len() as u32) };
2383 if n <= 0 {
2384 None
2385 } else {
2386 Some(buf[..n as usize].to_vec())
2387 }
2388}
2389
2390pub const WS_CONNECTING: u32 = 0;
2394pub const WS_OPEN: u32 = 1;
2396pub const WS_CLOSING: u32 = 2;
2398pub const WS_CLOSED: u32 = 3;
2400
2401pub struct WsMessage {
2403 pub is_binary: bool,
2405 pub data: Vec<u8>,
2407}
2408
2409impl WsMessage {
2410 pub fn text(&self) -> String {
2412 String::from_utf8_lossy(&self.data).to_string()
2413 }
2414}
2415
2416pub fn ws_connect(url: &str) -> u32 {
2422 unsafe { _api_ws_connect(url.as_ptr() as u32, url.len() as u32) }
2423}
2424
2425pub fn ws_send_text(id: u32, text: &str) -> i32 {
2429 unsafe { _api_ws_send_text(id, text.as_ptr() as u32, text.len() as u32) }
2430}
2431
2432pub fn ws_send_binary(id: u32, data: &[u8]) -> i32 {
2436 unsafe { _api_ws_send_binary(id, data.as_ptr() as u32, data.len() as u32) }
2437}
2438
2439pub fn ws_recv(id: u32) -> Option<WsMessage> {
2445 let mut buf = vec![0u8; 64 * 1024];
2446 let result = unsafe { _api_ws_recv(id, buf.as_mut_ptr() as u32, buf.len() as u32) };
2447 if result < 0 {
2448 return None;
2449 }
2450 let len = (result & 0xFFFF_FFFF) as usize;
2451 let is_binary = (result >> 32) & 1 == 1;
2452 Some(WsMessage {
2453 is_binary,
2454 data: buf[..len].to_vec(),
2455 })
2456}
2457
2458pub fn ws_ready_state(id: u32) -> u32 {
2462 unsafe { _api_ws_ready_state(id) }
2463}
2464
2465pub fn ws_close(id: u32) -> i32 {
2472 unsafe { _api_ws_close(id) }
2473}
2474
2475pub fn ws_remove(id: u32) {
2480 unsafe { _api_ws_remove(id) }
2481}
2482
2483pub fn midi_input_count() -> u32 {
2487 unsafe { _api_midi_input_count() }
2488}
2489
2490pub fn midi_output_count() -> u32 {
2492 unsafe { _api_midi_output_count() }
2493}
2494
2495pub fn midi_input_name(index: u32) -> String {
2499 let mut buf = [0u8; 128];
2500 let len = unsafe { _api_midi_input_name(index, buf.as_mut_ptr() as u32, buf.len() as u32) };
2501 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2502}
2503
2504pub fn midi_output_name(index: u32) -> String {
2508 let mut buf = [0u8; 128];
2509 let len = unsafe { _api_midi_output_name(index, buf.as_mut_ptr() as u32, buf.len() as u32) };
2510 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2511}
2512
2513pub fn midi_open_input(index: u32) -> u32 {
2518 unsafe { _api_midi_open_input(index) }
2519}
2520
2521pub fn midi_open_output(index: u32) -> u32 {
2525 unsafe { _api_midi_open_output(index) }
2526}
2527
2528pub fn midi_send(handle: u32, data: &[u8]) -> i32 {
2532 unsafe { _api_midi_send(handle, data.as_ptr() as u32, data.len() as u32) }
2533}
2534
2535pub fn midi_recv(handle: u32) -> Option<Vec<u8>> {
2542 let mut buf = [0u8; 256];
2543 let n = unsafe { _api_midi_recv(handle, buf.as_mut_ptr() as u32, buf.len() as u32) };
2544 if n >= 0 {
2545 return Some(buf[..n as usize].to_vec());
2546 }
2547 if n == -2 {
2549 let mut big = vec![0u8; 64 * 1024];
2550 let n2 = unsafe { _api_midi_recv(handle, big.as_mut_ptr() as u32, big.len() as u32) };
2551 if n2 >= 0 {
2552 big.truncate(n2 as usize);
2553 return Some(big);
2554 }
2555 }
2556 None
2557}
2558
2559pub fn midi_close(handle: u32) {
2561 unsafe { _api_midi_close(handle) }
2562}
2563
2564pub struct FetchResponse {
2568 pub status: u32,
2569 pub body: Vec<u8>,
2570}
2571
2572impl FetchResponse {
2573 pub fn text(&self) -> String {
2575 String::from_utf8_lossy(&self.body).to_string()
2576 }
2577}
2578
2579pub fn fetch(
2585 method: &str,
2586 url: &str,
2587 content_type: &str,
2588 body: &[u8],
2589) -> Result<FetchResponse, i64> {
2590 let mut out_buf = vec![0u8; 4 * 1024 * 1024]; let result = unsafe {
2592 _api_fetch(
2593 method.as_ptr() as u32,
2594 method.len() as u32,
2595 url.as_ptr() as u32,
2596 url.len() as u32,
2597 content_type.as_ptr() as u32,
2598 content_type.len() as u32,
2599 body.as_ptr() as u32,
2600 body.len() as u32,
2601 out_buf.as_mut_ptr() as u32,
2602 out_buf.len() as u32,
2603 )
2604 };
2605 if result < 0 {
2606 return Err(result);
2607 }
2608 let status = (result >> 32) as u32;
2609 let body_len = (result & 0xFFFF_FFFF) as usize;
2610 Ok(FetchResponse {
2611 status,
2612 body: out_buf[..body_len].to_vec(),
2613 })
2614}
2615
2616pub fn fetch_get(url: &str) -> Result<FetchResponse, i64> {
2618 fetch("GET", url, "", &[])
2619}
2620
2621pub fn fetch_post(url: &str, content_type: &str, body: &[u8]) -> Result<FetchResponse, i64> {
2623 fetch("POST", url, content_type, body)
2624}
2625
2626pub fn fetch_post_proto(url: &str, msg: &proto::ProtoEncoder) -> Result<FetchResponse, i64> {
2628 fetch("POST", url, "application/protobuf", msg.as_bytes())
2629}
2630
2631pub fn fetch_put(url: &str, content_type: &str, body: &[u8]) -> Result<FetchResponse, i64> {
2633 fetch("PUT", url, content_type, body)
2634}
2635
2636pub fn fetch_delete(url: &str) -> Result<FetchResponse, i64> {
2638 fetch("DELETE", url, "", &[])
2639}
2640
2641pub const FETCH_PENDING: u32 = 0;
2651pub const FETCH_STREAMING: u32 = 1;
2653pub const FETCH_DONE: u32 = 2;
2655pub const FETCH_ERROR: u32 = 3;
2657pub const FETCH_ABORTED: u32 = 4;
2659
2660pub enum FetchChunk {
2662 Data(Vec<u8>),
2665 Pending,
2668 End,
2670 Error,
2673}
2674
2675pub fn fetch_begin(method: &str, url: &str, content_type: &str, body: &[u8]) -> u32 {
2684 unsafe {
2685 _api_fetch_begin(
2686 method.as_ptr() as u32,
2687 method.len() as u32,
2688 url.as_ptr() as u32,
2689 url.len() as u32,
2690 content_type.as_ptr() as u32,
2691 content_type.len() as u32,
2692 body.as_ptr() as u32,
2693 body.len() as u32,
2694 )
2695 }
2696}
2697
2698pub fn fetch_begin_get(url: &str) -> u32 {
2700 fetch_begin("GET", url, "", &[])
2701}
2702
2703pub fn fetch_state(handle: u32) -> u32 {
2705 unsafe { _api_fetch_state(handle) }
2706}
2707
2708pub fn fetch_status(handle: u32) -> u32 {
2710 unsafe { _api_fetch_status(handle) }
2711}
2712
2713pub fn fetch_recv_into(handle: u32, buf: &mut [u8]) -> i64 {
2723 unsafe { _api_fetch_recv(handle, buf.as_mut_ptr() as u32, buf.len() as u32) }
2724}
2725
2726pub fn fetch_recv(handle: u32) -> FetchChunk {
2731 let mut buf = vec![0u8; 64 * 1024];
2732 let n = fetch_recv_into(handle, &mut buf);
2733 match n {
2734 -1 => FetchChunk::Pending,
2735 -2 => FetchChunk::End,
2736 -3 | -4 => FetchChunk::Error,
2737 n if n >= 0 => {
2738 buf.truncate(n as usize);
2739 FetchChunk::Data(buf)
2740 }
2741 _ => FetchChunk::Error,
2742 }
2743}
2744
2745pub fn fetch_error(handle: u32) -> Option<String> {
2747 let mut buf = [0u8; 512];
2748 let n = unsafe { _api_fetch_error(handle, buf.as_mut_ptr() as u32, buf.len() as u32) };
2749 if n < 0 {
2750 None
2751 } else {
2752 Some(String::from_utf8_lossy(&buf[..n as usize]).into_owned())
2753 }
2754}
2755
2756pub fn fetch_abort(handle: u32) -> bool {
2761 unsafe { _api_fetch_abort(handle) != 0 }
2762}
2763
2764pub fn fetch_remove(handle: u32) {
2769 unsafe { _api_fetch_remove(handle) }
2770}
2771
2772pub fn load_module(url: &str) -> i32 {
2778 unsafe { _api_load_module(url.as_ptr() as u32, url.len() as u32) }
2779}
2780
2781pub fn hash_sha256(data: &[u8]) -> [u8; 32] {
2785 let mut out = [0u8; 32];
2786 unsafe {
2787 _api_hash_sha256(
2788 data.as_ptr() as u32,
2789 data.len() as u32,
2790 out.as_mut_ptr() as u32,
2791 );
2792 }
2793 out
2794}
2795
2796pub fn hash_sha256_hex(data: &[u8]) -> String {
2798 let hash = hash_sha256(data);
2799 let mut hex = String::with_capacity(64);
2800 for byte in &hash {
2801 hex.push(HEX_CHARS[(*byte >> 4) as usize]);
2802 hex.push(HEX_CHARS[(*byte & 0x0F) as usize]);
2803 }
2804 hex
2805}
2806
2807const HEX_CHARS: [char; 16] = [
2808 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
2809];
2810
2811pub fn base64_encode(data: &[u8]) -> String {
2815 let mut buf = vec![0u8; data.len() * 4 / 3 + 8];
2816 let len = unsafe {
2817 _api_base64_encode(
2818 data.as_ptr() as u32,
2819 data.len() as u32,
2820 buf.as_mut_ptr() as u32,
2821 buf.len() as u32,
2822 )
2823 };
2824 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2825}
2826
2827pub fn base64_decode(encoded: &str) -> Vec<u8> {
2829 let mut buf = vec![0u8; encoded.len()];
2830 let len = unsafe {
2831 _api_base64_decode(
2832 encoded.as_ptr() as u32,
2833 encoded.len() as u32,
2834 buf.as_mut_ptr() as u32,
2835 buf.len() as u32,
2836 )
2837 };
2838 buf[..len as usize].to_vec()
2839}
2840
2841pub fn kv_store_set(key: &str, value: &[u8]) -> bool {
2846 let rc = unsafe {
2847 _api_kv_store_set(
2848 key.as_ptr() as u32,
2849 key.len() as u32,
2850 value.as_ptr() as u32,
2851 value.len() as u32,
2852 )
2853 };
2854 rc == 0
2855}
2856
2857pub fn kv_store_set_str(key: &str, value: &str) -> bool {
2859 kv_store_set(key, value.as_bytes())
2860}
2861
2862pub fn kv_store_get(key: &str) -> Option<Vec<u8>> {
2865 let mut buf = vec![0u8; 64 * 1024]; let rc = unsafe {
2867 _api_kv_store_get(
2868 key.as_ptr() as u32,
2869 key.len() as u32,
2870 buf.as_mut_ptr() as u32,
2871 buf.len() as u32,
2872 )
2873 };
2874 if rc < 0 {
2875 return None;
2876 }
2877 Some(buf[..rc as usize].to_vec())
2878}
2879
2880pub fn kv_store_get_str(key: &str) -> Option<String> {
2882 kv_store_get(key).map(|v| String::from_utf8_lossy(&v).into_owned())
2883}
2884
2885pub fn kv_store_delete(key: &str) -> bool {
2887 let rc = unsafe { _api_kv_store_delete(key.as_ptr() as u32, key.len() as u32) };
2888 rc == 0
2889}
2890
2891pub fn navigate(url: &str) -> i32 {
2897 unsafe { _api_navigate(url.as_ptr() as u32, url.len() as u32) }
2898}
2899
2900pub fn push_state(state: &[u8], title: &str, url: &str) {
2908 unsafe {
2909 _api_push_state(
2910 state.as_ptr() as u32,
2911 state.len() as u32,
2912 title.as_ptr() as u32,
2913 title.len() as u32,
2914 url.as_ptr() as u32,
2915 url.len() as u32,
2916 )
2917 }
2918}
2919
2920pub fn replace_state(state: &[u8], title: &str, url: &str) {
2923 unsafe {
2924 _api_replace_state(
2925 state.as_ptr() as u32,
2926 state.len() as u32,
2927 title.as_ptr() as u32,
2928 title.len() as u32,
2929 url.as_ptr() as u32,
2930 url.len() as u32,
2931 )
2932 }
2933}
2934
2935pub fn get_url() -> String {
2937 let mut buf = [0u8; 4096];
2938 let len = unsafe { _api_get_url(buf.as_mut_ptr() as u32, buf.len() as u32) };
2939 String::from_utf8_lossy(&buf[..len as usize]).to_string()
2940}
2941
2942pub fn get_state() -> Option<Vec<u8>> {
2945 let mut buf = vec![0u8; 64 * 1024]; let rc = unsafe { _api_get_state(buf.as_mut_ptr() as u32, buf.len() as u32) };
2947 if rc < 0 {
2948 return None;
2949 }
2950 Some(buf[..rc as usize].to_vec())
2951}
2952
2953pub fn history_length() -> u32 {
2955 unsafe { _api_history_length() }
2956}
2957
2958pub fn history_back() -> bool {
2960 unsafe { _api_history_back() == 1 }
2961}
2962
2963pub fn history_forward() -> bool {
2965 unsafe { _api_history_forward() == 1 }
2966}
2967
2968pub fn register_hyperlink(x: f32, y: f32, w: f32, h: f32, url: &str) -> i32 {
2976 unsafe { _api_register_hyperlink(x, y, w, h, url.as_ptr() as u32, url.len() as u32) }
2977}
2978
2979pub fn clear_hyperlinks() {
2981 unsafe { _api_clear_hyperlinks() }
2982}
2983
2984pub fn url_resolve(base: &str, relative: &str) -> Option<String> {
2989 let mut buf = [0u8; 4096];
2990 let rc = unsafe {
2991 _api_url_resolve(
2992 base.as_ptr() as u32,
2993 base.len() as u32,
2994 relative.as_ptr() as u32,
2995 relative.len() as u32,
2996 buf.as_mut_ptr() as u32,
2997 buf.len() as u32,
2998 )
2999 };
3000 if rc < 0 {
3001 return None;
3002 }
3003 Some(String::from_utf8_lossy(&buf[..rc as usize]).to_string())
3004}
3005
3006pub fn url_encode(input: &str) -> String {
3008 let mut buf = vec![0u8; input.len() * 3 + 4];
3009 let len = unsafe {
3010 _api_url_encode(
3011 input.as_ptr() as u32,
3012 input.len() as u32,
3013 buf.as_mut_ptr() as u32,
3014 buf.len() as u32,
3015 )
3016 };
3017 String::from_utf8_lossy(&buf[..len as usize]).to_string()
3018}
3019
3020pub fn url_decode(input: &str) -> String {
3022 let mut buf = vec![0u8; input.len() + 4];
3023 let len = unsafe {
3024 _api_url_decode(
3025 input.as_ptr() as u32,
3026 input.len() as u32,
3027 buf.as_mut_ptr() as u32,
3028 buf.len() as u32,
3029 )
3030 };
3031 String::from_utf8_lossy(&buf[..len as usize]).to_string()
3032}
3033
3034pub fn mouse_position() -> (f32, f32) {
3038 let packed = unsafe { _api_mouse_position() };
3039 let x = f32::from_bits((packed >> 32) as u32);
3040 let y = f32::from_bits((packed & 0xFFFF_FFFF) as u32);
3041 (x, y)
3042}
3043
3044pub fn mouse_button_down(button: u32) -> bool {
3047 unsafe { _api_mouse_button_down(button) != 0 }
3048}
3049
3050pub fn mouse_button_clicked(button: u32) -> bool {
3052 unsafe { _api_mouse_button_clicked(button) != 0 }
3053}
3054
3055pub fn key_down(key: u32) -> bool {
3058 unsafe { _api_key_down(key) != 0 }
3059}
3060
3061pub fn key_pressed(key: u32) -> bool {
3063 unsafe { _api_key_pressed(key) != 0 }
3064}
3065
3066pub fn scroll_delta() -> (f32, f32) {
3068 let packed = unsafe { _api_scroll_delta() };
3069 let x = f32::from_bits((packed >> 32) as u32);
3070 let y = f32::from_bits((packed & 0xFFFF_FFFF) as u32);
3071 (x, y)
3072}
3073
3074pub fn modifiers() -> u32 {
3076 unsafe { _api_modifiers() }
3077}
3078
3079pub fn shift_held() -> bool {
3081 modifiers() & 1 != 0
3082}
3083
3084pub fn ctrl_held() -> bool {
3086 modifiers() & 2 != 0
3087}
3088
3089pub fn alt_held() -> bool {
3091 modifiers() & 4 != 0
3092}
3093
3094pub const KEY_A: u32 = 0;
3097pub const KEY_B: u32 = 1;
3098pub const KEY_C: u32 = 2;
3099pub const KEY_D: u32 = 3;
3100pub const KEY_E: u32 = 4;
3101pub const KEY_F: u32 = 5;
3102pub const KEY_G: u32 = 6;
3103pub const KEY_H: u32 = 7;
3104pub const KEY_I: u32 = 8;
3105pub const KEY_J: u32 = 9;
3106pub const KEY_K: u32 = 10;
3107pub const KEY_L: u32 = 11;
3108pub const KEY_M: u32 = 12;
3109pub const KEY_N: u32 = 13;
3110pub const KEY_O: u32 = 14;
3111pub const KEY_P: u32 = 15;
3112pub const KEY_Q: u32 = 16;
3113pub const KEY_R: u32 = 17;
3114pub const KEY_S: u32 = 18;
3115pub const KEY_T: u32 = 19;
3116pub const KEY_U: u32 = 20;
3117pub const KEY_V: u32 = 21;
3118pub const KEY_W: u32 = 22;
3119pub const KEY_X: u32 = 23;
3120pub const KEY_Y: u32 = 24;
3121pub const KEY_Z: u32 = 25;
3122pub const KEY_0: u32 = 26;
3123pub const KEY_1: u32 = 27;
3124pub const KEY_2: u32 = 28;
3125pub const KEY_3: u32 = 29;
3126pub const KEY_4: u32 = 30;
3127pub const KEY_5: u32 = 31;
3128pub const KEY_6: u32 = 32;
3129pub const KEY_7: u32 = 33;
3130pub const KEY_8: u32 = 34;
3131pub const KEY_9: u32 = 35;
3132pub const KEY_ENTER: u32 = 36;
3133pub const KEY_ESCAPE: u32 = 37;
3134pub const KEY_TAB: u32 = 38;
3135pub const KEY_BACKSPACE: u32 = 39;
3136pub const KEY_DELETE: u32 = 40;
3137pub const KEY_SPACE: u32 = 41;
3138pub const KEY_UP: u32 = 42;
3139pub const KEY_DOWN: u32 = 43;
3140pub const KEY_LEFT: u32 = 44;
3141pub const KEY_RIGHT: u32 = 45;
3142pub const KEY_HOME: u32 = 46;
3143pub const KEY_END: u32 = 47;
3144pub const KEY_PAGE_UP: u32 = 48;
3145pub const KEY_PAGE_DOWN: u32 = 49;
3146
3147pub fn ui_button(id: u32, x: f32, y: f32, w: f32, h: f32, label: &str) -> bool {
3155 unsafe { _api_ui_button(id, x, y, w, h, label.as_ptr() as u32, label.len() as u32) != 0 }
3156}
3157
3158pub fn ui_checkbox(id: u32, x: f32, y: f32, label: &str, initial: bool) -> bool {
3162 unsafe {
3163 _api_ui_checkbox(
3164 id,
3165 x,
3166 y,
3167 label.as_ptr() as u32,
3168 label.len() as u32,
3169 if initial { 1 } else { 0 },
3170 ) != 0
3171 }
3172}
3173
3174pub fn ui_slider(id: u32, x: f32, y: f32, w: f32, min: f32, max: f32, initial: f32) -> f32 {
3178 unsafe { _api_ui_slider(id, x, y, w, min, max, initial) }
3179}
3180
3181pub fn ui_text_input(id: u32, x: f32, y: f32, w: f32, initial: &str) -> String {
3185 let mut buf = [0u8; 4096];
3186 let len = unsafe {
3187 _api_ui_text_input(
3188 id,
3189 x,
3190 y,
3191 w,
3192 initial.as_ptr() as u32,
3193 initial.len() as u32,
3194 buf.as_mut_ptr() as u32,
3195 buf.len() as u32,
3196 )
3197 };
3198 String::from_utf8_lossy(&buf[..len as usize]).to_string()
3199}