servo-script-bindings 0.2.0

A component of the servo web-engine.
Documentation
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use std::cell::Cell;
use std::marker::PhantomData;
use std::ops::Deref;

use js::context::JSContext as SafeJSContext;
use js::jsapi::JSContext as RawJSContext;
use js::realm::{AutoRealm, CurrentRealm};

#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct JSContext(*mut RawJSContext);

impl From<&mut SafeJSContext> for JSContext {
    fn from(safe_cx: &mut SafeJSContext) -> Self {
        unsafe { JSContext(safe_cx.raw_cx()) }
    }
}

impl<'a> From<&mut CurrentRealm<'a>> for JSContext {
    fn from(safe_cx: &mut CurrentRealm<'a>) -> Self {
        unsafe { JSContext(safe_cx.raw_cx()) }
    }
}

impl<'a> From<&mut AutoRealm<'a>> for JSContext {
    fn from(safe_cx: &mut AutoRealm<'a>) -> Self {
        unsafe { JSContext(safe_cx.raw_cx()) }
    }
}

#[expect(unsafe_code)]
impl JSContext {
    /// Create a new [`JSContext`] object from the given raw pointer.
    ///
    /// # Safety
    ///
    /// The `RawJSContext` argument must point to a valid `RawJSContext` in memory.
    pub unsafe fn from_ptr(raw_js_context: *mut RawJSContext) -> Self {
        JSContext(raw_js_context)
    }

    /// For compatibility with [js::context::JSContext]
    pub fn raw_cx(&self) -> *mut RawJSContext {
        self.0
    }

    /// For compatibility with [js::context::JSContext]
    pub fn raw_cx_no_gc(&self) -> *mut RawJSContext {
        self.0
    }
}

impl Deref for JSContext {
    type Target = *mut RawJSContext;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

thread_local!(
    static THREAD_ACTIVE: Cell<bool> = const { Cell::new(true) };
);

pub fn runtime_is_alive() -> bool {
    THREAD_ACTIVE.with(|t| t.get())
}

pub fn mark_runtime_dead() {
    THREAD_ACTIVE.with(|t| t.set(false));
}

/// Get the current JSContext for the running thread.
///
/// ## Safety
/// Using this function is unsafe because no other JSContext may be constructed apart from initial ones,
/// but because we are still working on passing down &mut SafeJSContext references,
/// this function is provided as temporary workaround/placeholder.
///
/// As such all it's usages will need to be eventually replaced with proper &mut SafeJSContext references.
pub unsafe fn temp_cx() -> SafeJSContext {
    unsafe { SafeJSContext::from_ptr(js::rust::Runtime::get().unwrap()) }
}

#[derive(Clone, Copy, Debug)]
/// A compile-time marker that there are operations that could trigger a JS garbage collection
/// operation within the current stack frame. It is trivially copyable, so it should be passed
/// as a function argument and reused when calling other functions whenever possible. Since it
/// is only meaningful within the current stack frame, it is impossible to move it to a different
/// thread or into a task that will execute asynchronously.
pub struct CanGc(PhantomData<*mut ()>);

impl CanGc {
    /// Create a new CanGc value, representing that a GC operation is possible within the
    /// current stack frame.
    ///
    /// Deprecrated: do not use. Instead, use [`CanGc::from_cx(cx)`] with a `cx` from a task
    /// callback or by declaring it in Bindings.conf.
    pub fn deprecated_note() -> CanGc {
        CanGc(PhantomData)
    }

    /// &mut SafeJSContext is always an indication that GC is possible.
    pub fn from_cx(_cx: &mut SafeJSContext) -> CanGc {
        CanGc::deprecated_note()
    }
}