1#![deny(clippy::panic, clippy::panicking_unwrap)]
6#![warn(clippy::std_instead_of_alloc, clippy::std_instead_of_core)]
7
8extern crate alloc;
9extern crate core;
10
11use alloc::string::String;
12use core::fmt;
13
14use serde::Serialize;
15use wasm_bindgen::prelude::*;
16
17use crate::util::value_to_string;
18#[macro_use]
19pub(crate) mod private;
20
21mod api;
22mod binding;
23mod env;
24mod memory;
25mod session;
26mod tensor;
27mod util;
28
29pub use self::{
30 session::sync_outputs,
31 tensor::{SyncDirection, ValueExt}
32};
33
34pub type Result<T, E = Error> = core::result::Result<T, E>;
35
36#[derive(Debug, Clone)]
37pub struct Error {
38 msg: String
39}
40
41impl Error {
42 pub(crate) fn new(msg: impl Into<String>) -> Self {
43 Self { msg: msg.into() }
44 }
45}
46
47impl From<JsValue> for Error {
48 fn from(value: JsValue) -> Self {
49 Self::new(value_to_string(&value))
50 }
51}
52
53impl fmt::Display for Error {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 self.msg.fmt(f)
56 }
57}
58
59impl core::error::Error for Error {}
60
61pub const FEATURE_NONE: u8 = 0;
63pub const FEATURE_WEBGL: u8 = 1 << 0;
67pub const FEATURE_WEBGPU: u8 = 1 << 1;
71pub const FEATURE_WEBNN: u8 = FEATURE_WEBGPU;
75
76pub async fn api<L: Loadable>(config: L) -> Result<ort_sys::OrtApi> {
109 let (features, dist) = config.into_features_and_dist()?;
110 binding::init_runtime(features, dist).await?;
111
112 Ok(self::api::api())
113}
114
115pub trait Loadable {
116 #[doc(hidden)]
117 fn into_features_and_dist(self) -> Result<(u8, JsValue)>;
118}
119
120impl Loadable for u8 {
121 fn into_features_and_dist(self) -> Result<(u8, JsValue)> {
122 Ok((self, JsValue::null()))
123 }
124}
125
126impl Loadable for Dist {
127 fn into_features_and_dist(self) -> Result<(u8, JsValue)> {
128 Ok((0, serde_wasm_bindgen::to_value(&self).map_err(|e| Error::new(e.to_string()))?))
129 }
130}
131
132#[derive(Default, Debug, Serialize, Clone)]
133#[serde(rename_all = "camelCase")]
134pub struct Integrities {
135 main: Option<String>,
136 wrapper: Option<String>,
137 binary: Option<String>
138}
139
140impl Integrities {
141 pub fn set_main(&mut self, hash: impl Into<String>) {
143 self.main = Some(hash.into());
144 }
145
146 pub fn set_wrapper(&mut self, hash: impl Into<String>) {
148 self.wrapper = Some(hash.into());
149 }
150
151 pub fn set_binary(&mut self, hash: impl Into<String>) {
153 self.binary = Some(hash.into());
154 }
155}
156
157#[derive(Debug, Serialize, Clone)]
158#[serde(rename_all = "camelCase")]
159pub struct Dist {
160 base_url: String,
161 script_name: String,
162 binary_name: Option<String>,
163 wrapper_name: Option<String>,
164 integrities: Integrities
165}
166
167impl Dist {
168 pub fn new(base_url: impl Into<String>) -> Self {
169 Self {
170 base_url: base_url.into(),
171 script_name: "ort.wasm.min.js".to_string(),
172 binary_name: None,
173 wrapper_name: None,
174 integrities: Integrities::default()
175 }
176 }
177
178 pub fn with_script_name(mut self, name: impl Into<String>) -> Self {
180 self.script_name = name.into();
181 self
182 }
183
184 pub fn with_binary_name(mut self, name: impl Into<String>) -> Self {
186 self.binary_name = Some(name.into());
187 self
188 }
189
190 pub fn with_wrapper_name(mut self, name: impl Into<String>) -> Self {
193 self.wrapper_name = Some(name.into());
194 self
195 }
196
197 pub fn integrities(&mut self) -> &mut Integrities {
199 &mut self.integrities
200 }
201}