1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use futures::{future, Future, Poll, Async, task};
use wasm_bindgen::{JsValue, JsCast, closure::Closure};
#[inline]
fn factory() -> web_sys::IdbFactory {
web_sys::window().unwrap().indexed_db().unwrap().unwrap()
}
#[derive(Debug)]
pub struct Db {
inner: web_sys::IdbDatabase,
}
pub fn open(name: &str, version: u32) -> impl Future<Item=Db, Error=JsValue> {
if version == 0 {
panic!("indexeddb version must be >= 1");
}
match IdbOpenDbRequest::open(name, version) {
Ok(f) => Box::new(f) as Box<dyn Future<Item=Db, Error=JsValue>>,
Err(e) => Box::new(future::err(e)) as Box<dyn Future<Item=Db, Error=JsValue>>
}
}
struct IdbOpenDbRequest {
inner: web_sys::IdbOpenDbRequest,
onsuccess: Option<Closure<FnMut()>>,
onerror: Option<Closure<FnMut()>>,
}
impl IdbOpenDbRequest {
fn open(name: &str, version: u32) -> Result<IdbOpenDbRequest, JsValue> {
let inner = factory().open_with_u32(name, version)?;
Ok(IdbOpenDbRequest {
inner,
onsuccess: None,
onerror: None,
})
}
}
impl Future for IdbOpenDbRequest {
type Item = Db;
type Error = JsValue;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
use web_sys::IdbRequestReadyState as ReadyState;
match self.inner.ready_state() {
ReadyState::Pending => {
let success_notifier = task::current();
let error_notifier = success_notifier.clone();
let onsuccess = Closure::wrap(Box::new(move || {
success_notifier.notify();
}) as Box<FnMut()>);
self.inner.set_onsuccess(Some(onsuccess.as_ref().unchecked_ref()));
self.onsuccess.replace(onsuccess); let onerror = Closure::wrap(Box::new(move || {
error_notifier.notify();
}) as Box<FnMut()>);
self.inner.set_onerror(Some(&onerror.as_ref().unchecked_ref()));
self.onerror.replace(onerror); Ok(Async::NotReady)
},
ReadyState::Done => {
match self.inner.result() {
Ok(val) => Ok(Async::Ready(Db { inner: val.unchecked_into() })),
Err(_) => match self.inner.error() {
Ok(Some(e)) => Err(e.into()),
Ok(None) => unreachable!("internal error polling open db request"),
Err(e) => Err(e)
}
}
},
_ => panic!("unexpected ready state")
}
}
}