n5_wasm/
lib.rs

1extern crate cfg_if;
2extern crate futures;
3extern crate js_sys;
4extern crate n5;
5extern crate serde_json;
6extern crate wasm_bindgen;
7extern crate wasm_bindgen_futures;
8extern crate web_sys;
9
10mod utils;
11
12use std::io::{
13    Error,
14    ErrorKind,
15};
16
17use js_sys::Promise;
18use futures::{future, Future};
19use wasm_bindgen::prelude::*;
20use wasm_bindgen_futures::future_to_promise;
21
22use n5::prelude::*;
23
24
25pub mod http_fetch;
26
27
28pub trait N5PromiseReader {
29    /// Get the N5 specification version of the container.
30    fn get_version(&self) -> Promise;
31
32    fn get_dataset_attributes(&self, path_name: &str) -> Promise;
33
34    fn exists(&self, path_name: &str) -> Promise;
35
36    fn dataset_exists(&self, path_name: &str) -> Promise;
37
38    fn read_block(
39        &self,
40        path_name: &str,
41        data_attrs: &wrapped::DatasetAttributes,
42        grid_position: Vec<i64>
43    ) -> Promise;
44
45    fn list_attributes(&self, path_name: &str) -> Promise;
46}
47
48impl<T> N5PromiseReader for T where T: N5AsyncReader {
49    fn get_version(&self) -> Promise {
50        let to_return = self.get_version()
51            .map(|v| JsValue::from(wrapped::Version(v)));
52
53        future_to_promise(map_future_error_wasm(to_return))
54    }
55
56    fn get_dataset_attributes(&self, path_name: &str) -> Promise {
57        let to_return = self.get_dataset_attributes(path_name)
58            .map(|da| JsValue::from(wrapped::DatasetAttributes(da)));
59
60        future_to_promise(map_future_error_wasm(to_return))
61    }
62
63    fn exists(&self, path_name: &str) -> Promise {
64        let to_return = self.exists(path_name)
65            .map(JsValue::from);
66
67        future_to_promise(map_future_error_wasm(to_return))
68    }
69
70    fn dataset_exists(&self, path_name: &str) -> Promise {
71        let to_return = self.dataset_exists(path_name)
72            .map(JsValue::from);
73
74        future_to_promise(map_future_error_wasm(to_return))
75    }
76
77    fn read_block(
78        &self,
79        path_name: &str,
80        data_attrs: &wrapped::DatasetAttributes,
81        grid_position: Vec<i64>
82    ) -> Promise {
83        match data_attrs.0.get_data_type() {
84            // TODO: presumably can be rid of these monomorphization kludges
85            // when GATs land.
86            DataType::UINT8 => future_to_promise(map_future_error_wasm(
87                self.read_block::<u8>(path_name, &data_attrs.0, grid_position)
88                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockUINT8::from))))),
89            DataType::UINT16 => future_to_promise(map_future_error_wasm(
90                self.read_block::<u16>(path_name, &data_attrs.0, grid_position)
91                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockUINT16::from))))),
92            DataType::UINT32 => future_to_promise(map_future_error_wasm(
93                self.read_block::<u32>(path_name, &data_attrs.0, grid_position)
94                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockUINT32::from))))),
95            DataType::UINT64 => future_to_promise(map_future_error_wasm(
96                self.read_block::<u64>(path_name, &data_attrs.0, grid_position)
97                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockUINT64::from))))),
98            DataType::INT8 => future_to_promise(map_future_error_wasm(
99                self.read_block::<i8>(path_name, &data_attrs.0, grid_position)
100                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockINT8::from))))),
101            DataType::INT16 => future_to_promise(map_future_error_wasm(
102                self.read_block::<i16>(path_name, &data_attrs.0, grid_position)
103                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockINT16::from))))),
104            DataType::INT32 => future_to_promise(map_future_error_wasm(
105                self.read_block::<i32>(path_name, &data_attrs.0, grid_position)
106                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockINT32::from))))),
107            DataType::INT64 => future_to_promise(map_future_error_wasm(
108                self.read_block::<i64>(path_name, &data_attrs.0, grid_position)
109                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockINT64::from))))),
110            DataType::FLOAT32 => future_to_promise(map_future_error_wasm(
111                self.read_block::<f32>(path_name, &data_attrs.0, grid_position)
112                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockFLOAT32::from))))),
113            DataType::FLOAT64 => future_to_promise(map_future_error_wasm(
114                self.read_block::<f64>(path_name, &data_attrs.0, grid_position)
115                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockFLOAT64::from))))),
116        }
117    }
118
119    fn list_attributes(
120        &self,
121        path_name: &str,
122    ) -> Promise {
123
124        // TODO: Superfluous conversion from JSON to JsValue to serde to JsValue.
125        let to_return = self.list_attributes(path_name)
126            .map(|v| JsValue::from_serde(&v).unwrap());
127
128        future_to_promise(map_future_error_wasm(to_return))
129    }
130}
131
132
133pub trait N5PromiseEtagReader {
134    fn block_etag(
135        &self,
136        path_name: &str,
137        data_attrs: &wrapped::DatasetAttributes,
138        grid_position: Vec<i64>
139    ) -> Promise;
140
141    fn read_block_with_etag(
142        &self,
143        path_name: &str,
144        data_attrs: &wrapped::DatasetAttributes,
145        grid_position: Vec<i64>
146    ) -> Promise;
147}
148
149impl<T> N5PromiseEtagReader for T where T: N5AsyncEtagReader {
150    fn block_etag(
151        &self,
152        path_name: &str,
153        data_attrs: &wrapped::DatasetAttributes,
154        grid_position: Vec<i64>
155    ) -> Promise {
156        let to_return = self.block_etag(path_name, &data_attrs.0, grid_position)
157            .map(JsValue::from);
158
159        future_to_promise(map_future_error_wasm(to_return))
160    }
161
162    fn read_block_with_etag(
163        &self,
164        path_name: &str,
165        data_attrs: &wrapped::DatasetAttributes,
166        grid_position: Vec<i64>
167    ) -> Promise {
168        match data_attrs.0.get_data_type() {
169            // TODO: presumably can be rid of these monomorphization kludges
170            // when GATs land.
171            DataType::UINT8 => future_to_promise(map_future_error_wasm(
172                self.read_block_with_etag::<u8>(path_name, &data_attrs.0, grid_position)
173                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockUINT8::from))))),
174            DataType::UINT16 => future_to_promise(map_future_error_wasm(
175                self.read_block_with_etag::<u16>(path_name, &data_attrs.0, grid_position)
176                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockUINT16::from))))),
177            DataType::UINT32 => future_to_promise(map_future_error_wasm(
178                self.read_block_with_etag::<u32>(path_name, &data_attrs.0, grid_position)
179                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockUINT32::from))))),
180            DataType::UINT64 => future_to_promise(map_future_error_wasm(
181                self.read_block_with_etag::<u64>(path_name, &data_attrs.0, grid_position)
182                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockUINT64::from))))),
183            DataType::INT8 => future_to_promise(map_future_error_wasm(
184                self.read_block_with_etag::<i8>(path_name, &data_attrs.0, grid_position)
185                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockINT8::from))))),
186            DataType::INT16 => future_to_promise(map_future_error_wasm(
187                self.read_block_with_etag::<i16>(path_name, &data_attrs.0, grid_position)
188                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockINT16::from))))),
189            DataType::INT32 => future_to_promise(map_future_error_wasm(
190                self.read_block_with_etag::<i32>(path_name, &data_attrs.0, grid_position)
191                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockINT32::from))))),
192            DataType::INT64 => future_to_promise(map_future_error_wasm(
193                self.read_block_with_etag::<i64>(path_name, &data_attrs.0, grid_position)
194                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockINT64::from))))),
195            DataType::FLOAT32 => future_to_promise(map_future_error_wasm(
196                self.read_block_with_etag::<f32>(path_name, &data_attrs.0, grid_position)
197                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockFLOAT32::from))))),
198            DataType::FLOAT64 => future_to_promise(map_future_error_wasm(
199                self.read_block_with_etag::<f64>(path_name, &data_attrs.0, grid_position)
200                    .map(|maybe_block| JsValue::from(maybe_block.map(VecDataBlockFLOAT64::from))))),
201        }
202    }
203}
204
205
206/// This trait exists to preserve type information between calls (rather than
207/// erasing it with `Promise`) and for easier potential future compatibility
208/// with an N5 core async trait.
209pub trait N5AsyncReader {
210    fn get_version(&self) -> Box<Future<Item = n5::Version, Error = Error>>;
211
212    fn get_dataset_attributes(&self, path_name: &str) ->
213        Box<Future<Item = n5::DatasetAttributes, Error = Error>>;
214
215    fn exists(&self, path_name: &str) -> Box<Future<Item = bool, Error = Error>>;
216
217    fn dataset_exists(&self, path_name: &str) -> Box<Future<Item = bool, Error = Error>> {
218        Box::new(self.exists(path_name).join(
219            self.get_dataset_attributes(path_name)
220                .map(|_| true)
221                .or_else(|_| futures::future::ok(false))
222        ).map(|(exists, has_attr)| exists && has_attr))
223    }
224
225    fn read_block<T>(
226        &self,
227        path_name: &str,
228        data_attrs: &DatasetAttributes,
229        grid_position: Vec<i64>
230    ) -> Box<Future<Item = Option<VecDataBlock<T>>, Error = Error>>
231            where DataType: n5::DataBlockCreator<T>,
232                  VecDataBlock<T>: DataBlock<T>,
233                  T: Clone + 'static;
234
235    fn list(&self, path_name: &str) -> Box<Future<Item = Vec<String>, Error = Error>>;
236
237    fn list_attributes(&self, path_name: &str) -> Box<Future<Item = serde_json::Value, Error = Error>>;
238}
239
240
241pub trait N5AsyncEtagReader {
242    fn block_etag(
243        &self,
244        path_name: &str,
245        data_attrs: &DatasetAttributes,
246        grid_position: Vec<i64>
247    ) -> Box<Future<Item = Option<String>, Error = Error>>;
248
249    fn read_block_with_etag<T>(
250        &self,
251        path_name: &str,
252        data_attrs: &DatasetAttributes,
253        grid_position: Vec<i64>
254    ) -> Box<Future<Item = Option<(VecDataBlock<T>, Option<String>)>, Error = Error>>
255            where DataType: n5::DataBlockCreator<T>,
256                  VecDataBlock<T>: DataBlock<T>,
257                  T: Clone + 'static;
258}
259
260
261fn map_future_error_rust<F: Future<Item = T, Error = JsValue>, T>(future: F)
262        -> impl Future<Item = T, Error = Error> {
263    future.map_err(convert_jsvalue_error)
264}
265
266fn map_future_error_wasm<F: Future<Item = T, Error = Error>, T>(future: F)
267        -> impl Future<Item = T, Error = JsValue> {
268    future.map_err(|error| {
269        let js_error = js_sys::Error::new(&format!("{:?}", error));
270        JsValue::from(js_error)
271    })
272}
273
274fn convert_jsvalue_error(error: JsValue) -> Error {
275    Error::new(std::io::ErrorKind::Other, format!("{:?}", error))
276}
277
278
279pub mod wrapped {
280    use super::*;
281
282    #[wasm_bindgen]
283    pub struct Version(pub(crate) n5::Version);
284
285    #[wasm_bindgen]
286    impl Version {
287        pub fn to_string(&self) -> String {
288            self.0.to_string()
289        }
290    }
291
292    #[wasm_bindgen]
293    pub struct DatasetAttributes(pub(crate) n5::DatasetAttributes);
294
295    #[wasm_bindgen]
296    impl DatasetAttributes {
297        pub fn get_dimensions(&self) -> Vec<i64> {
298            self.0.get_dimensions().to_owned()
299        }
300
301        pub fn get_block_size(&self) -> Vec<i32> {
302            self.0.get_block_size().to_owned()
303        }
304
305        pub fn get_data_type(&self) -> String {
306            self.0.get_data_type().to_string()
307        }
308
309        pub fn get_compression(&self) -> String {
310            self.0.get_compression().to_string()
311        }
312
313        pub fn get_ndim(&self) -> usize {
314            self.0.get_ndim()
315        }
316
317        /// Get the total number of elements possible given the dimensions.
318        pub fn get_num_elements(&self) -> usize {
319            self.0.get_num_elements()
320        }
321
322        /// Get the total number of elements possible in a block.
323        pub fn get_block_num_elements(&self) -> usize {
324            self.0.get_block_num_elements()
325        }
326    }
327}
328
329macro_rules! data_block_monomorphizer {
330    ($d_name:ident, $d_type:ty) => {
331        #[wasm_bindgen]
332        pub struct $d_name(VecDataBlock<$d_type>, Option<String>);
333
334        impl From<VecDataBlock<$d_type>> for $d_name {
335            fn from(block: VecDataBlock<$d_type>) -> Self {
336                $d_name(block, None)
337            }
338        }
339
340        impl From<(VecDataBlock<$d_type>, Option<String>)> for $d_name {
341            fn from((block, etag): (VecDataBlock<$d_type>, Option<String>)) -> Self {
342                $d_name(block, etag)
343            }
344        }
345
346        #[wasm_bindgen]
347        impl $d_name {
348            pub fn get_size(&self) -> Vec<i32> {
349                self.0.get_size().to_owned()
350            }
351
352            pub fn get_grid_position(&self) -> Vec<i64> {
353                self.0.get_grid_position().to_owned()
354            }
355
356            pub fn get_data(&self) -> Vec<$d_type> {
357                self.0.get_data().to_owned()
358            }
359
360            pub fn into_data(self) -> Vec<$d_type> {
361                self.0.into()
362            }
363
364            pub fn get_num_elements(&self) -> i32 {
365                self.0.get_num_elements()
366            }
367
368            pub fn get_etag(&self) -> Option<String> {
369                self.1.to_owned()
370            }
371        }
372    }
373}
374
375data_block_monomorphizer!(VecDataBlockUINT8,  u8);
376data_block_monomorphizer!(VecDataBlockUINT16, u16);
377data_block_monomorphizer!(VecDataBlockUINT32, u32);
378data_block_monomorphizer!(VecDataBlockUINT64, u64);
379data_block_monomorphizer!(VecDataBlockINT8,  i8);
380data_block_monomorphizer!(VecDataBlockINT16, i16);
381data_block_monomorphizer!(VecDataBlockINT32, i32);
382data_block_monomorphizer!(VecDataBlockINT64, i64);
383data_block_monomorphizer!(VecDataBlockFLOAT32, f32);
384data_block_monomorphizer!(VecDataBlockFLOAT64, f64);