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
This commit is contained in:
Nika Layzell 2022-09-13 13:47:13 +00:00
Родитель 73e787acd3
Коммит 2d7346701a
6 изменённых файлов: 128 добавлений и 3 удалений

Просмотреть файл

@ -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.

Просмотреть файл

@ -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
)

Просмотреть файл

@ -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"],
)

Просмотреть файл

@ -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;
}
}

Просмотреть файл

@ -0,0 +1,23 @@
/* 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"));

Просмотреть файл

@ -38,6 +38,9 @@ pub mod interfaces;
// XPCOM service getters.
pub mod services;
// XPCOM component getters.
pub mod components;
// Implementation details of the xpcom_macros crate.
#[doc(hidden)]
pub mod reexports;