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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#![feature(async_await, await_macro, futures_api)]
#![recursion_limit="500"]

#[macro_use]
extern crate stdweb;

use stdweb::PromiseFuture;
use stdweb::Value;
use stdweb::unstable::TryInto;
use stdweb::unstable::TryFrom;


pub enum Driver {
  INDEXEDDB,
  WEBSQL,
  LOCALSTORAGE,
}

impl TryFrom<Driver> for Value {
  type Error = ();
  fn try_from(driver: Driver) -> Result<Value, Self::Error> {
    match driver {
      Driver::INDEXEDDB => Ok(js! ( return localforage.INDEXEDDB;  )),
      Driver::WEBSQL => Ok(js! ( return localforage.WEBSQL;  )),
      Driver::LOCALSTORAGE => Ok(js! ( return localforage.LOCALSTORAGE; )),
    }
  }
}

pub struct LocalForage {
  obj: Value,
}

pub struct Config {
  pub name: Option<String>,
  pub driver: Option<Driver>,
  pub size: Option<u32>,
  pub store_name: Option<String>,
  pub version: Option<String>,
  pub description: Option<String>,
}

impl LocalForage {
  pub fn new(name: String) -> Self {
    LocalForage { obj: js! ( return localforage.createInstance({name: @{name}});  ) }
  }

  pub fn get_item<T>(&self, key: &str) -> PromiseFuture<T> where <T as TryFrom<Value>>::Error: std::fmt::Debug, T: TryFrom<Value> + 'static {
    js! ( return @{&self.obj}.getItem(@{key}); ).try_into().unwrap()
  }

  pub fn set_item<T>(&self, key: &str, value: T) -> PromiseFuture<T>
    where T: TryInto<Value> + TryFrom<Value> + 'static,
    <T as TryInto<Value>>::Error: std::fmt::Debug,
    <T as TryFrom<Value>>::Error: std::fmt::Debug {

    let tmp: Value = value.try_into().unwrap();
    js! ( return @{&self.obj}.setItem(@{key}, @{tmp}); ).try_into().unwrap()
  }

  pub fn remove_item(&self, key: &str) -> PromiseFuture<()> {
    js! ( return @{&self.obj}.removeItem(@{key}); ).try_into().unwrap()
  }

  pub fn clear(&self) -> PromiseFuture<()> {
    js! ( return @{&self.obj}.clear(); ).try_into().unwrap()
  }

  pub fn length(&self) -> PromiseFuture<u64> {
    js! ( return @{&self.obj}.length();  ).try_into().unwrap()
  }

  pub fn keys(&self) -> PromiseFuture<Vec<String>> {
    js! ( return @{&self.obj}.keys();  ).try_into().unwrap()
  }

  pub fn drop_instance(&self) -> PromiseFuture<()> {
      js! ( return @{&self.obj}.dropInstance();  ).try_into().unwrap()
  }

  pub fn set_driver(&self, driver: Driver) {
    js! { @{&self.obj}.setDriver(@{Value::try_from(driver).unwrap()});  };
  }

  pub fn config(&self, config: Config) {
    js! {
      let config = {};
      if @{config.name.is_some()} { config.name = @{config.name.unwrap()};  }
      if @{config.driver.is_some()} { config.driver = @{Value::try_from(config.driver.unwrap()).unwrap()};  }
      if @{config.size.is_some()} { config.size = @{config.size.unwrap()};  }
      if @{config.store_name.is_some()} { config.name = @{config.store_name.unwrap()};  }
      if @{config.version.is_some()} { config.version = @{config.version.unwrap()};  }
      if @{config.description.is_some()} { config.description = @{config.description.unwrap()};  }
        @{&self.obj}.config(config);
    };
  }
}