jstime_core/
lib.rs

1#[macro_use]
2extern crate lazy_static;
3
4mod builtins;
5mod isolate_state;
6mod js_loading;
7mod module;
8mod script;
9
10pub(crate) use isolate_state::IsolateState;
11
12pub fn init(v8_flags: Option<Vec<String>>) {
13    if let Some(mut v8_flags) = v8_flags {
14        v8_flags.push("jstime".to_owned());
15        v8_flags.rotate_right(1);
16
17        v8::V8::set_flags_from_command_line(v8_flags);
18    }
19
20    let platform = v8::new_default_platform(0, false).make_shared();
21    v8::V8::initialize_platform(platform);
22    v8::V8::initialize();
23}
24
25/// Options for `JSTime::new`.
26#[derive(Default)]
27pub struct Options {
28    // pub snapshot: Option<&'static [u8]>,
29    // taking_snapshot: bool,
30}
31
32impl Options {
33    pub fn new(_snapshot: Option<&'static [u8]>) -> Options {
34        Options {
35            // snapshot,
36            // ..Options::default()
37        }
38    }
39}
40
41/// JSTime Instance.
42#[allow(clippy::all)]
43pub struct JSTime {
44    isolate: Option<v8::OwnedIsolate>,
45    // taking_snapshot: bool,
46}
47
48impl JSTime {
49    /// Create a new JSTime instance from `options`.
50    pub fn new(options: Options) -> JSTime {
51        let create_params =
52            v8::Isolate::create_params().external_references(&**builtins::EXTERNAL_REFERENCES);
53        // if let Some(snapshot) = options.snapshot {
54        // create_params = create_params.snapshot_blob(snapshot);
55        // }
56        let isolate = v8::Isolate::new(create_params);
57        JSTime::create(options, isolate)
58    }
59
60    // pub fn create_snapshot(mut options: Options) -> Vec<u8> {
61    //     assert!(
62    //         options.snapshot.is_none(),
63    //         "Cannot pass snapshot data while creating snapshot"
64    //     );
65    //     options.taking_snapshot = true;
66
67    //     let mut s = v8::SnapshotCreator::new(Some(&builtins::EXTERNAL_REFERENCES));
68
69    //     {
70    //         let mut jstime = JSTime::create(options, unsafe { s.get_owned_isolate() });
71    //         {
72    //             let context = IsolateState::get(jstime.isolate()).borrow().context();
73    //             let scope = &mut v8::HandleScope::new(jstime.isolate());
74    //             let context = v8::Local::new(scope, context);
75    //             s.set_default_context(context);
76    //         }
77    //         // Context needs to be dropped before create_blob
78    //         IsolateState::get(jstime.isolate())
79    //             .borrow_mut()
80    //             .drop_context();
81    //     }
82
83    //     match s.create_blob(v8::FunctionCodeHandling::Keep) {
84    //         Some(data) => data.to_owned(),
85    //         None => {
86    //             // dropping SnapshotCreator will panic if it failed, and
87    //             // we're going to panic here anyway, so just forget it.
88    //             std::mem::forget(s);
89    //             panic!("Unable to create snapshot");
90    //         }
91    //     }
92    // }
93
94    fn create(_options: Options, mut isolate: v8::OwnedIsolate) -> JSTime {
95        let global_context = {
96            let scope = &mut v8::HandleScope::new(&mut isolate);
97            let context = v8::Context::new(scope);
98            v8::Global::new(scope, context)
99        };
100
101        isolate.set_slot(IsolateState::new(global_context));
102
103        // If snapshot data was provided, the builtins already exist within it.
104        if true {
105            let context = IsolateState::get(&mut isolate).borrow().context();
106            let scope = &mut v8::HandleScope::with_context(&mut isolate, context);
107            builtins::Builtins::create(scope);
108        }
109
110        JSTime {
111            isolate: Some(isolate),
112            // taking_snapshot: options.taking_snapshot,
113        }
114    }
115
116    fn isolate(&mut self) -> &mut v8::Isolate {
117        match self.isolate.as_mut() {
118            Some(i) => i,
119            None => unsafe {
120                std::hint::unreachable_unchecked();
121            },
122        }
123    }
124
125    /// Import a module by filename.
126    pub fn import(&mut self, filename: &str) -> Result<(), String> {
127        let context = IsolateState::get(self.isolate()).borrow().context();
128        let scope = &mut v8::HandleScope::with_context(self.isolate(), context);
129        let loader = module::Loader::new();
130
131        let mut cwd = std::env::current_dir().unwrap();
132        cwd.push("jstime");
133        let cwd = cwd.into_os_string().into_string().unwrap();
134        match loader.import(scope, &cwd, filename) {
135            Ok(_) => Ok(()),
136            Err(e) => Err(e.to_string(scope).unwrap().to_rust_string_lossy(scope)),
137        }
138    }
139
140    /// Run a script and get a string representation of the result.
141    pub fn run_script(&mut self, source: &str, filename: &str) -> Result<String, String> {
142        let context = IsolateState::get(self.isolate()).borrow().context();
143        let scope = &mut v8::HandleScope::with_context(self.isolate(), context);
144        match script::run(scope, source, filename) {
145            Ok(v) => Ok(v.to_string(scope).unwrap().to_rust_string_lossy(scope)),
146            Err(e) => Err(e.to_string(scope).unwrap().to_rust_string_lossy(scope)),
147        }
148    }
149}
150
151impl Drop for JSTime {
152    fn drop(&mut self) {
153        // if self.taking_snapshot {
154        // The isolate is not actually owned by JSTime if we're
155        // snapshotting, it's owned by the SnapshotCreator.
156        // std::mem::forget(self.isolate.take().unwrap())
157        // }
158    }
159}