Bug 1779326 - Handle a few more native types in rust-xpidl, r=xpcom-reviewers,kmag, a=dmeehan

This makes the logic for the rust type line up a bit more with the C++
logic for existing types, and adds support for 'char' and 'char16_t'
native types (for 'charPtr').

This specifically enables `nsIInputStream::Read` to be used from Rust.

Differential Revision: https://phabricator.services.mozilla.com/D152715
This commit is contained in:
Nika Layzell 2022-07-27 14:09:52 +00:00
parent 73a19e7b18
commit 643863e174
7 changed files with 64 additions and 36 deletions

View File

@ -58,7 +58,7 @@ impl MyObserver {
&self,
_subject: *const nsISupports,
_topic: *const c_char,
_data: *const i16,
_data: *const u16,
) -> nsresult {
self.ran.store(true, Ordering::SeqCst);
nserror::NS_OK

View File

@ -105,13 +105,13 @@ fn ensure_observing_shutdown() {
struct InitShutdownObserver {}
impl ShutdownObserver {
xpcom_method!(observe => Observe(_subject: *const nsISupports, topic: *const c_char, _data: *const i16));
xpcom_method!(observe => Observe(_subject: *const nsISupports, topic: *const c_char, _data: *const u16));
/// Remove our shutdown observer and clear the map.
fn observe(
&self,
_subject: &nsISupports,
topic: *const c_char,
_data: *const i16,
_data: *const u16,
) -> Result<(), nsresult> {
LOGGERS_BY_TARGET.write().unwrap().clear();
if let Some(service) = xpcom::services::get_ObserverService() {

View File

@ -59,7 +59,7 @@ impl UploadPrefObserver {
&self,
_subject: *const nsISupports,
topic: *const c_char,
pref_name: *const i16,
pref_name: *const u16,
) -> nserror::nsresult {
let topic = CStr::from_ptr(topic).to_str().unwrap();
// Conversion utf16 to utf8 is messy.
@ -69,7 +69,7 @@ impl UploadPrefObserver {
// cargo-culted from https://searchfox.org/mozilla-central/rev/598e50d2c3cd81cd616654f16af811adceb08f9f/security/manager/ssl/cert_storage/src/lib.rs#1606-1612
// (with a little transformation)
let len = (0..).take_while(|&i| *pref_name.offset(i) != 0).count(); // find NUL.
let slice = std::slice::from_raw_parts(pref_name as *const u16, len);
let slice = std::slice::from_raw_parts(pref_name, len);
let pref_name = match String::from_utf16(slice) {
Ok(name) => name,
Err(_) => return NS_ERROR_FAILURE,

View File

@ -69,7 +69,7 @@ impl UserActivityObserver {
&self,
_subject: *const nsISupports,
topic: *const c_char,
_data: *const i16,
_data: *const u16,
) -> nserror::nsresult {
match CStr::from_ptr(topic).to_str() {
Ok("user-interaction-active") => self.handle_active(),

View File

@ -201,7 +201,7 @@ impl ProfileChangeObserver {
&self,
_subject: *const nsISupports,
_topic: *const c_char,
_data: *const i16,
_data: *const u16,
) -> nsresult {
update_profile_dir();
NS_OK

View File

@ -194,8 +194,8 @@ builtinNames = [
Builtin("double", "double", "libc::c_double", True, False),
Builtin("char", "char", "libc::c_char", True, False),
Builtin("string", "char *", "*const libc::c_char", False, False),
Builtin("wchar", "char16_t", "i16", False, False),
Builtin("wstring", "char16_t *", "*const i16", False, False),
Builtin("wchar", "char16_t", "u16", False, False),
Builtin("wstring", "char16_t *", "*const u16", False, False),
]
builtinMap = {}
@ -621,7 +621,7 @@ class Native(object):
def rustType(self, calltype, const=False, shared=False):
# For the most part, 'native' types don't make sense in rust, as they
# are native C++ types. However, we can support a few types here, as
# they're important.
# they're important and can easily be translated.
#
# NOTE: This code doesn't try to perfectly match C++ constness, as
# constness doesn't affect ABI, and raw pointers are already unsafe.
@ -629,33 +629,61 @@ class Native(object):
if self.modifier not in ["ptr", "ref"]:
raise RustNoncompat("Rust only supports [ref] / [ptr] native types")
prefix = "*mut " if "out" in calltype else "*const "
if "out" in calltype and self.modifier == "ptr":
prefix += "*mut "
if shared:
if calltype != "out":
raise IDLError(
"[shared] only applies to out parameters.", self.location
)
const = True
if self.specialtype == "nsid":
if "element" in calltype:
if self.isPtr(calltype):
raise IDLError(
"Array<nsIDPtr> not yet supported. "
"File an XPConnect bug if you need it.",
self.location,
)
return self.nativename
return prefix + self.nativename
if self.specialtype in ["cstring", "utf8string"]:
if "element" in calltype:
return "::nsstring::nsCString"
return prefix + "::nsstring::nsACString"
if self.specialtype == "astring":
if "element" in calltype:
return "::nsstring::nsString"
return prefix + "::nsstring::nsAString"
if self.nativename == "void":
return prefix + "libc::c_void"
# 'in' nsid parameters should be made 'const'
if self.specialtype == "nsid" and calltype == "in":
const = True
prefix = "*const " if const or shared else "*mut "
if "out" in calltype and self.isPtr(calltype):
prefix = "*mut " + prefix
if self.specialtype:
raise RustNoncompat("specialtype %s unsupported" % self.specialtype)
# The string types are very special, and need to be handled seperately.
if self.specialtype in ["cstring", "utf8string"]:
if calltype == "in":
return "*const ::nsstring::nsACString"
elif "out" in calltype:
return "*mut ::nsstring::nsACString"
else:
return "::nsstring::nsCString"
if self.specialtype == "astring":
if calltype == "in":
return "*const ::nsstring::nsAString"
elif "out" in calltype:
return "*mut ::nsstring::nsAString"
else:
return "::nsstring::nsString"
# nsid has some special handling, but generally re-uses the generic
# prefix handling above.
if self.specialtype == "nsid":
if "element" in calltype:
if self.isPtr(calltype):
raise IDLError(
"Array<nsIDPtr> not yet supported. "
"File an XPConnect bug if you need it.",
self.location,
)
return self.nativename
return prefix + self.nativename
raise RustNoncompat("special type %s unsupported" % self.specialtype)
# These 3 special types correspond to native pointer types which can
# generally be supported behind pointers. Other types are not supported
# for now.
if self.nativename == "void":
return prefix + "libc::c_void"
if self.nativename == "char":
return prefix + "libc::c_char"
if self.nativename == "char16_t":
return prefix + "u16"
raise RustNoncompat("native type %s unsupported" % self.nativename)
def __str__(self):

View File

@ -31,7 +31,7 @@ pub unsafe extern "C" fn Rust_ObserveFromRust() -> *const interfaces::nsIObserve
&self,
_subject: *const interfaces::nsISupports,
topic: *const c_char,
_data: *const i16,
_data: *const u16,
) -> nsresult {
*self.run = true;
assert!(CStr::from_ptr(topic).to_str() == Ok("test-rust-observe"));
@ -118,7 +118,7 @@ pub unsafe extern "C" fn Rust_GetMultipleInterfaces(
&self,
_subject: *const interfaces::nsISupports,
_topic: *const c_char,
_data: *const i16,
_data: *const u16,
) -> nsresult {
NS_OK
}