Commit 2d734670 authored by Nika Layzell's avatar Nika Layzell
Browse files

Bug 1789902 - Part 1: Support accessing XPCOM static components from Rust, r=xpcom-reviewers,barret

This will allow us to replace some of the uses of Services.py with the
non-deprecated static components getters.

Differential Revision: https://phabricator.services.mozilla.com/D156890
parent 73e787ac
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -52,11 +52,12 @@ reflects `nsresult` codes into Rust.
- [xpcom](https://searchfox.org/mozilla-central/source/xpcom/rust/xpcom/src)
  provides multiple building blocks for a component's implementation.
  - The `RefPtr` type is for managing reference-counted pointers.
  - XPCOM service getters are generated by
    [xpcom/build/Services.py](https://searchfox.org/mozilla-central/source/xpcom/build/Services.py)
  - XPCOM component getters are generated by
    [xpcom/components/gen_static_components.py](https://searchfox.org/mozilla-central/source/xpcom/components/gen_static_components.py),
    and can be called like this:
    ```
    let pref_service = xpcom::services::get_PrefService();
    use xpcom::{interfaces::nsIPrefService, RefPtr};
    let pref_service: RefPtr<nsIPrefService> = xpcom::components::Preferences::service()?;
    ```
  - There is also a `get_service` function that works like `do_GetService` in
    C++, as an alternative.
+78 −0
Original line number Diff line number Diff line
@@ -521,6 +521,57 @@ static inline ::mozilla::xpcom::CreateInstanceHelper Create(nsresult* aRv = null

        return res

    # Generates the rust code for the `xpcom::components::<name>` entry
    # corresponding to this component. This may not be called for modules
    # without an explicit `name` (in which cases, `self.anonymous` will be
    # true).
    def lower_getters_rust(self):
        assert not self.anonymous

        substs = {
            "name": self.name,
            "id": "super::ModuleID::%s" % self.name,
        }

        res = (
            """
#[allow(non_snake_case)]
pub mod %(name)s {
    /// Get the singleton service instance for this component.
    pub fn service<T: crate::XpCom>() -> Result<crate::RefPtr<T>, nserror::nsresult> {
        let mut ga = crate::GetterAddrefs::<T>::new();
        let rv = unsafe { super::Gecko_GetServiceByModuleID(%(id)s, &T::IID, ga.void_ptr()) };
        if rv.failed() {
            return Err(rv);
        }
        ga.refptr().ok_or(nserror::NS_ERROR_NO_INTERFACE)
    }
"""
            % substs
        )

        if not self.singleton:
            res += (
                """
    /// Create a new instance of this component.
    pub fn create<T: crate::XpCom>() -> Result<crate::RefPtr<T>, nserror::nsresult> {
        let mut ga = crate::GetterAddrefs::<T>::new();
        let rv = unsafe { super::Gecko_CreateInstanceByModuleID(%(id)s, &T::IID, ga.void_ptr()) };
        if rv.failed() {
            return Err(rv);
        }
        ga.refptr().ok_or(nserror::NS_ERROR_NO_INTERFACE)
    }
"""
                % substs
            )

        res += """\
}
"""

        return res


# Returns a quoted string literal representing the given raw string, with
# certain special characters replaced so that it can be used in a C++-style
@@ -678,6 +729,17 @@ def gen_getters(entries):
    return "".join(entry.lower_getters() for entry in entries if not entry.anonymous)


# Generates the rust getter code for each named component entry in the
# `xpcom::components::` module.
def gen_getters_rust(entries):
    entries = list(entries)
    entries.sort(key=lambda e: e.name)

    return "".join(
        entry.lower_getters_rust() for entry in entries if not entry.anonymous
    )


def gen_includes(substs, all_headers):
    headers = set()
    absolute_headers = set()
@@ -843,6 +905,8 @@ def gen_substs(manifests):

    substs["component_getters"] = gen_getters(cid_phf.entries)

    substs["component_getters_rust"] = gen_getters_rust(cid_phf.entries)

    substs["module_cid_table"] = cid_phf.cxx_codegen(
        name="ModuleByCID",
        entry_type="StaticModule",
@@ -964,6 +1028,20 @@ static constexpr size_t kModuleInitCount = %(init_count)d;
}  // namespace mozilla

#endif
"""
            % substs
        )

    with open_output("components.rs") as fh:
        fh.write(
            """\
/// Unique IDs for each statically-registered module.
#[repr(u16)]
pub enum ModuleID {
%(module_ids)s
}

%(component_getters_rust)s
"""
            % substs
        )
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ if CONFIG["COMPILE_ENVIRONMENT"]:
        "StaticComponentData.h",
        "StaticComponents.cpp",
        "services.json",
        "components.rs",
        script="gen_static_components.py",
        inputs=["!manifest-lists.json", "StaticComponents.cpp.in"],
    )
+19 −0
Original line number Diff line number Diff line
@@ -1557,4 +1557,23 @@ const nsIServiceManager* Gecko_GetServiceManager() {
const nsIComponentRegistrar* Gecko_GetComponentRegistrar() {
  return nsComponentManagerImpl::gComponentManager;
}

// FFI-compatible version of `GetServiceHelper::operator()`.
nsresult Gecko_GetServiceByModuleID(ModuleID aId, const nsIID* aIID,
                                    void** aResult) {
  return nsComponentManagerImpl::gComponentManager->GetService(aId, *aIID,
                                                               aResult);
}

// FFI-compatible version of `CreateInstanceHelper::operator()`.
nsresult Gecko_CreateInstanceByModuleID(ModuleID aId, const nsIID* aIID,
                                        void** aResult) {
  const auto& entry = gStaticModules[size_t(aId)];
  if (!entry.Active()) {
    return NS_ERROR_FACTORY_NOT_REGISTERED;
  }

  nsresult rv = entry.CreateInstance(*aIID, aResult);
  return rv;
}
}
+23 −0
Original line number Diff line number Diff line
/* 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 http://mozilla.org/MPL/2.0/. */

//! This module contains convenient accessors for static XPCOM components.
//!
//! The contents of this file are generated from
//! `xpcom/components/gen_static_components.py`.

extern "C" {
    fn Gecko_GetServiceByModuleID(
        id: ModuleID,
        iid: &crate::nsIID,
        result: *mut *mut libc::c_void,
    ) -> nserror::nsresult;
    fn Gecko_CreateInstanceByModuleID(
        id: ModuleID,
        iid: &crate::nsIID,
        result: *mut *mut libc::c_void,
    ) -> nserror::nsresult;
}

include!(mozbuild::objdir_path!("xpcom/components/components.rs"));
Loading