Hadi gidelim.
Rust'ta WebAssembly(Wasm) modülleri için TypeScript türleri oluşturmak kolay değildir.
Wasm'da Voy adında bir vektör benzerlik arama motoru üzerinde çalışırken bu sorunla karşılaştım. Wasm motorunu, JavaScript ve TypeScript mühendislerine anlamsal arama için İsviçre bıçağı sağlamak üzere Rust'ta geliştirdim. İşte web için bir demo:
Voy'un deposunu GitHub'da bulabilirsiniz! Denemekten çekinmeyin.
Depoda Voy'un farklı çerçevelerde nasıl kullanılacağını görebileceğiniz örnekler yer alıyor.
Rust kodunu oluşturup Wasm'a derlemek için wasm-pack ve wasm-bindgen'i kullandım. Oluşturulan TypeScript tanımları şöyle görünür:
/* tslint:disable */ /* eslint-disable */ /** * @param {any} input * @returns {string} */ export function index(resource: any): string /** * @param {string} index * @param {any} query * @param {number} k * @returns {any} */ export function search(index: string, query: any, k: number): any
Gördüğünüz gibi çok sayıda "herhangi" türü var ve bu, geliştirici deneyimi için pek yararlı değil. Ne olduğunu öğrenmek için Rust koduna bakalım.
type NumberOfResult = usize; type Embeddings = Vec<f32>; type SerializedIndex = String; #[derive(Serialize, Deserialize, Debug)] pub struct EmbeddedResource { id: String, title: String, url: String, embeddings: Embeddings, } #[derive(Serialize, Deserialize, Debug)] pub struct Resource { pub embeddings: Vec<EmbeddedResource>, } #[wasm_bindgen] pub fn index(resource: JsValue) -> SerializedIndex { /* snip */ } #[wasm_bindgen] pub fn search(index: &str, query: JsValue, k: NumberOfResult) -> JsValue { // snip }
Dize, dilim ve işaretsiz tamsayı TypeScript'te doğru türleri oluşturdu ancak " wasm_bindgen::JsValue " oluşturmadı. JsValue wasm-bindgen'in bir JavaScript nesnesini temsilidir.
JsValue'yu, Wasm aracılığıyla JavaScript ve Rust arasında ileri geri aktarmak için seri hale getiriyoruz ve seri durumdan çıkarıyoruz .
#[wasm_bindgen] pub fn index(resource: JsValue) -> String { // 💡 Deserialize JsValue in to Resource struct in Rust let resource: Resource = serde_wasm_bindgen:from_value(input).unwrap(); // snip } #[wasm_bindgen] pub fn search(index: &str, query: JsValue, k: usize) -> JsValue { // snip // 💡 Serialize search result into JsValue and pass it to WebAssembly let result = engine::search(&index, &query, k).unwrap(); serde_wasm_bindgen:to_value(&result).unwrap() }
Veri türlerini dönüştürmek resmi yaklaşımdır, ancak açıkça TypeScript'i desteklemek için ekstra yol kat etmemiz gerekiyor.
Veri türlerini bir dilden diğerine dönüştürmek aslında Yabancı işlev arayüzü (FFI) adı verilen yaygın bir kalıptır. Rust yapılarından TypeScript tanımlarını otomatik olarak oluşturmak için Typeshare gibi FFI araçlarını araştırdım, ancak bu, çözümün yalnızca yarısıydı.
İhtiyacımız olan şey, Wasm derlemesinden yararlanmanın ve Wasm modülünün API'si için tür tanımını oluşturmanın bir yoludur. Bunun gibi:
#[wasm_bindgen] pub fn index(resource: Resource) -> SerializedIndex { /* snip */ } #[wasm_bindgen] pub fn search(index: SerializedIndex, query: Embeddings, k: NumberOfResult) -> SearchResult { // snip }
Neyse ki Tsify , kullanım durumu için harika bir açık kaynaklı kütüphanedir. Tek yapmamız gereken "Tsify" özelliğinden türetmek ve yapılara bir #[tsify] makrosu eklemek:
type NumberOfResult = usize; type Embeddings = Vec<f32>; type SerializedIndex = String; #[derive(Serialize, Deserialize, Debug, Clone, Tsify)] #[tsify(from_wasm_abi)] pub struct EmbeddedResource { pub id: String, pub title: String, pub url: String, pub embeddings: Embeddings, } #[derive(Serialize, Deserialize, Debug, Tsify)] #[tsify(from_wasm_abi)] pub struct Resource { pub embeddings: Vec<EmbeddedResource>, } #[derive(Serialize, Deserialize, Debug, Clone, Tsify)] #[tsify(into_wasm_abi)] pub struct Neighbor { pub id: String, pub title: String, pub url: String, } #[derive(Serialize, Deserialize, Debug, Clone, Tsify)] #[tsify(into_wasm_abi)] pub struct SearchResult { neighbors: Vec<Neighbor>, } #[wasm_bindgen] pub fn index(resource: Resource) -> SerializedIndex { /* snip */ } #[wasm_bindgen] pub fn search(index: SerializedIndex, query: Embeddings, k: NumberOfResult) -> SearchResult { // snip }
Bu kadar! "from_wasm_abi" ve "into_wasm_abi" niteliklerine bir göz atalım.
Her iki özellik de Rust veri türünü TypeScript tanımına dönüştürür. Farklı yaptıkları şey, Wasm'ın Uygulama İkili Arayüzü (ABI) ile veri akışının yönüdür.
Her iki özellik de Rust ve JavaScript arasındaki veri dönüşümünü uygulamak için serde-wasm-bindgen'i kullanır.
Wasm modülünü oluşturmaya hazırız. "Wasm-pack build"i çalıştırdığınızda, otomatik olarak oluşturulan TypeScript tanımı:
/* tslint:disable */ /* eslint-disable */ /** * @param {Resource} resource * @returns {string} */ export function index(resource: Resource): string /** * @param {string} index * @param {Float32Array} query * @param {number} k * @returns {SearchResult} */ export function search( index: string, query: Float32Array, k: number ): SearchResult export interface EmbeddedResource { id: string title: string url: string embeddings: number[] } export interface Resource { embeddings: EmbeddedResource[] } export interface Neighbor { id: string title: string url: string } export interface SearchResult { neighbors: Neighbor[] }
Tüm "herhangi" türler, Rust kodunda tanımladığımız arayüzlerle değiştirilir✨
Oluşturulan türler iyi görünüyor ancak bazı tutarsızlıklar var. Yakından bakarsanız, arama fonksiyonundaki sorgu parametresinin Float32Array olarak tanımlandığını fark edeceksiniz.
Sorgu parametresi EmbeddedResource'ta "gömmeler" ile aynı türde tanımlandığından TypeScript'te de aynı türe sahip olmalarını bekliyorum.
Neden farklı türlere dönüştürüldüklerini biliyorsanız, lütfen GitHub'daki Voy'a ulaşmaktan veya bir çekme isteği açmaktan çekinmeyin.
Voy , WebAssembly'deki açık kaynaklı bir anlamsal arama motorudur. Bunu, anlamsal özellikler geliştirmek ve dünyanın her yerindeki insanlar için daha iyi kullanıcı deneyimleri yaratmak amacıyla daha fazla projeye güç vermek için oluşturdum. Voy çeşitli tasarım ilkelerini takip eder:
Npm'de mevcuttur. Favori paket yöneticinizle kolayca kurabilirsiniz ve artık hazırsınız.
# with npm npm i voy-search # with Yarn yarn add voy-search # with pnpm pnpm add voy-search
Bir deneyin, sizden haber almaktan mutluluk duyuyorum!
Bağlanmak mı istiyorsunuz?
Bu makale ilk olarak Daw-Chih'in Web Sitesinde yayınlanmıştır.