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
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use std::ptr::{null_mut, NonNull};

use foreign_types::{ForeignType, ForeignTypeRef};

use crate::{ffi, Local, RuntimeRef, Value};

foreign_type! {
    /// `Context` represents a Javascript context (or Realm).
    ///
    /// Each `Context` has its own global objects and system objects.
    /// There can be several `Contexts` per `Runtime` and they can share objects,
    /// similary to frames of the same origin sharing Javascript objects in a web browser.
    pub type Context : Send {
        type CType = ffi::JSContext;

        fn drop = ffi::JS_FreeContext;
    }
}

impl_foreign_type!(Context, ContextRef);

pub struct Builder(Context);

impl Context {
    pub fn new(runtime: &RuntimeRef) -> Context {
        unsafe { Context::from_ptr(ffi::JS_NewContext(runtime.as_ptr())) }
    }

    pub fn builder(runtime: &RuntimeRef) -> Builder {
        Builder(unsafe { Context::from_ptr(ffi::JS_NewContextRaw(runtime.as_ptr())) })
    }
}

impl Builder {
    pub fn with_base_objects(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicBaseObjects(self.0.as_ptr()) };
        self
    }

    pub fn with_date(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicDate(self.0.as_ptr()) };
        self
    }

    pub fn with_eval(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicEval(self.0.as_ptr()) };
        self
    }

    pub fn with_string_normalize(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicStringNormalize(self.0.as_ptr()) };
        self
    }

    pub fn with_regexp_compiler(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicRegExpCompiler(self.0.as_ptr()) };
        self
    }

    pub fn with_regexp(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicRegExp(self.0.as_ptr()) };
        self
    }

    pub fn with_json(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicJSON(self.0.as_ptr()) };
        self
    }

    pub fn with_proxy(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicProxy(self.0.as_ptr()) };
        self
    }

    pub fn with_map(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicMapSet(self.0.as_ptr()) };
        self
    }

    pub fn with_typedarray(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicTypedArrays(self.0.as_ptr()) };
        self
    }

    pub fn with_promise(self) -> Self {
        unsafe { ffi::JS_AddIntrinsicPromise(self.0.as_ptr()) };
        self
    }

    pub fn build(self) -> Context {
        self.0
    }
}

impl ContextRef {
    pub fn runtime(&self) -> &RuntimeRef {
        unsafe { RuntimeRef::from_ptr(ffi::JS_GetRuntime(self.as_ptr())) }
    }

    pub fn userdata<T>(&self) -> Option<NonNull<T>> {
        NonNull::new(unsafe { ffi::JS_GetContextOpaque(self.as_ptr()) } as *mut _)
    }

    pub fn set_userdata<T>(&self, userdata: Option<NonNull<T>>) -> &Self {
        trace!("{:?} set userdata to {:?}", self, userdata);

        unsafe {
            ffi::JS_SetContextOpaque(
                self.as_ptr(),
                userdata.map_or_else(null_mut, |p| p.as_ptr() as *mut _),
            );
        }
        self
    }

    /// Set the maximum system stack size.
    pub fn set_max_stack_size(&self, stack_size: usize) -> &Self {
        trace!("{:?} set stack size to {:?}", self, stack_size);

        unsafe {
            ffi::JS_SetMaxStackSize(self.as_ptr(), stack_size);
        }
        self
    }

    pub fn global_object(&self) -> Local<Value> {
        self.bind(unsafe { ffi::JS_GetGlobalObject(self.as_ptr()) })
    }
}