tree_sitter/
wasm_language.rs1use std::{
2 error,
3 ffi::{CStr, CString},
4 fmt,
5 mem::{self, MaybeUninit},
6 os::raw::c_char,
7};
8
9pub use wasmtime_c_api::wasmtime;
10
11use crate::{ffi, Language, LanguageError, Parser, FREE_FN};
12
13#[allow(unused)]
16fn _use_wasmtime() {
17 wasmtime_c_api::wasm_engine_new();
18}
19
20#[repr(C)]
21#[derive(Clone)]
22#[allow(non_camel_case_types)]
23pub struct wasm_engine_t {
24 pub(crate) engine: wasmtime::Engine,
25}
26
27pub struct WasmStore(*mut ffi::TSWasmStore);
28
29unsafe impl Send for WasmStore {}
30unsafe impl Sync for WasmStore {}
31
32#[derive(Debug, PartialEq, Eq)]
33pub struct WasmError {
34 pub kind: WasmErrorKind,
35 pub message: String,
36}
37
38#[derive(Debug, PartialEq, Eq)]
39pub enum WasmErrorKind {
40 Parse,
41 Compile,
42 Instantiate,
43 Other,
44}
45
46impl WasmStore {
47 pub fn new(engine: &wasmtime::Engine) -> Result<Self, WasmError> {
48 unsafe {
49 let mut error = MaybeUninit::<ffi::TSWasmError>::uninit();
50 let store = ffi::ts_wasm_store_new(
51 std::ptr::from_ref::<wasmtime::Engine>(engine)
52 .cast_mut()
53 .cast(),
54 error.as_mut_ptr(),
55 );
56 if store.is_null() {
57 Err(WasmError::new(error.assume_init()))
58 } else {
59 Ok(Self(store))
60 }
61 }
62 }
63
64 pub fn load_language(&mut self, name: &str, bytes: &[u8]) -> Result<Language, WasmError> {
65 let name = CString::new(name).unwrap();
66 unsafe {
67 let mut error = MaybeUninit::<ffi::TSWasmError>::uninit();
68 let language = ffi::ts_wasm_store_load_language(
69 self.0,
70 name.as_ptr(),
71 bytes.as_ptr().cast::<c_char>(),
72 bytes.len() as u32,
73 error.as_mut_ptr(),
74 );
75 if language.is_null() {
76 Err(WasmError::new(error.assume_init()))
77 } else {
78 Ok(Language(language))
79 }
80 }
81 }
82
83 #[must_use]
84 pub fn language_count(&self) -> usize {
85 unsafe { ffi::ts_wasm_store_language_count(self.0) }
86 }
87}
88
89impl WasmError {
90 unsafe fn new(error: ffi::TSWasmError) -> Self {
91 let message = CStr::from_ptr(error.message).to_str().unwrap().to_string();
92 (FREE_FN)(error.message.cast());
93 Self {
94 kind: match error.kind {
95 ffi::TSWasmErrorKindParse => WasmErrorKind::Parse,
96 ffi::TSWasmErrorKindCompile => WasmErrorKind::Compile,
97 ffi::TSWasmErrorKindInstantiate => WasmErrorKind::Instantiate,
98 _ => WasmErrorKind::Other,
99 },
100 message,
101 }
102 }
103}
104
105impl Language {
106 #[must_use]
107 pub fn is_wasm(&self) -> bool {
108 unsafe { ffi::ts_language_is_wasm(self.0) }
109 }
110}
111
112impl Parser {
113 pub fn set_wasm_store(&mut self, store: WasmStore) -> Result<(), LanguageError> {
114 unsafe { ffi::ts_parser_set_wasm_store(self.0.as_ptr(), store.0) };
115 mem::forget(store);
116 Ok(())
117 }
118
119 pub fn take_wasm_store(&mut self) -> Option<WasmStore> {
120 let ptr = unsafe { ffi::ts_parser_take_wasm_store(self.0.as_ptr()) };
121 if ptr.is_null() {
122 None
123 } else {
124 Some(WasmStore(ptr))
125 }
126 }
127}
128
129impl Drop for WasmStore {
130 fn drop(&mut self) {
131 unsafe { ffi::ts_wasm_store_delete(self.0) };
132 }
133}
134
135impl fmt::Display for WasmError {
136 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137 let kind = match self.kind {
138 WasmErrorKind::Parse => "Failed to parse wasm",
139 WasmErrorKind::Compile => "Failed to compile wasm",
140 WasmErrorKind::Instantiate => "Failed to instantiate wasm module",
141 WasmErrorKind::Other => "Unknown error",
142 };
143 write!(f, "{kind}: {}", self.message)
144 }
145}
146
147impl error::Error for WasmError {}