Bug 1535377 - Allow the xpcom_method Rust macro to be used without importing ensure_param r=myk,froydnj
authorKirk Steuber <ksteuber@mozilla.com>
Mon, 25 Mar 2019 18:56:17 +0000
changeset 465992 d7fdd6fbd9cd6c019733f2b574c6ffb95ba81913
parent 465991 27b4670e5e9c2c4230a9d8089c6f9582f153d9ef
child 465993 d04ec06581a08f3b487f1becd6ef018424ef8139
push id35758
push userrgurzau@mozilla.com
push dateTue, 26 Mar 2019 09:51:47 +0000
treeherdermozilla-central@4572f6055a6a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmyk, froydnj
bugs1535377
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1535377 - Allow the xpcom_method Rust macro to be used without importing ensure_param r=myk,froydnj This is done by incorporating the ensure_param macro into the implementation of the xpcom_method macro Differential Revision: https://phabricator.services.mozilla.com/D23568
toolkit/components/kvstore/src/lib.rs
xpcom/rust/moz_task/src/lib.rs
xpcom/rust/xpcom/src/method.rs
--- a/toolkit/components/kvstore/src/lib.rs
+++ b/toolkit/components/kvstore/src/lib.rs
@@ -9,17 +9,16 @@ extern crate failure;
 extern crate libc;
 extern crate lmdb;
 extern crate log;
 extern crate moz_task;
 extern crate nserror;
 extern crate nsstring;
 extern crate rkv;
 extern crate storage_variant;
-#[macro_use]
 extern crate xpcom;
 
 mod error;
 mod owned_value;
 mod task;
 
 use atomic_refcell::AtomicRefCell;
 use error::KeyValueError;
@@ -35,17 +34,17 @@ use std::{
     vec::IntoIter,
 };
 use task::{DeleteTask, EnumerateTask, GetOrCreateTask, GetTask, HasTask, PutTask};
 use xpcom::{
     interfaces::{
         nsIKeyValueDatabaseCallback, nsIKeyValueEnumeratorCallback, nsIKeyValuePair,
         nsIKeyValueVariantCallback, nsIKeyValueVoidCallback, nsISupports, nsIThread, nsIVariant,
     },
-    nsIID, RefPtr, ThreadBoundRefPtr,
+    nsIID, RefPtr, ThreadBoundRefPtr, xpcom, xpcom_method,
 };
 
 type KeyValuePairResult = Result<(String, OwnedValue), KeyValueError>;
 
 #[no_mangle]
 pub unsafe extern "C" fn nsKeyValueServiceConstructor(
     outer: *const nsISupports,
     iid: &nsIID,
--- a/xpcom/rust/moz_task/src/lib.rs
+++ b/xpcom/rust/moz_task/src/lib.rs
@@ -6,30 +6,29 @@
 //! to make it safer and more convenient to call the XPCOM functions.
 //! It also provides the Task trait and TaskRunnable struct,
 //! which make it easier to dispatch tasks to threads.
 
 extern crate libc;
 extern crate memchr;
 extern crate nserror;
 extern crate nsstring;
-#[macro_use]
 extern crate xpcom;
 
 use nserror::{nsresult, NS_OK};
 use nsstring::{nsACString, nsCString};
 use std::{
     marker::PhantomData,
     mem, ptr,
     sync::atomic::{AtomicBool, Ordering},
 };
 use xpcom::{
     getter_addrefs,
     interfaces::{nsIEventTarget, nsIRunnable, nsISupports, nsIThread},
-    AtomicRefcnt, RefCounted, RefPtr, XpCom,
+    AtomicRefcnt, RefCounted, RefPtr, XpCom, xpcom, xpcom_method,
 };
 
 extern "C" {
     fn NS_GetCurrentThreadEventTarget(result: *mut *const nsIThread) -> nsresult;
     fn NS_GetMainThreadEventTarget(result: *mut *const nsIThread) -> nsresult;
     fn NS_IsMainThread() -> bool;
     fn NS_NewNamedThreadWithDefaultStackSize(
         name: *const nsACString,
--- a/xpcom/rust/xpcom/src/method.rs
+++ b/xpcom/rust/xpcom/src/method.rs
@@ -25,43 +25,46 @@ use nserror::{nsresult, NS_ERROR_NULL_PO
 /// #[derive(xpcom)]
 /// #[xpimplements(nsIFooBarBaz)]
 /// #[refcnt = "atomic"]
 /// struct InitFooBarBaz {
 ///     // …
 /// }
 /// ```
 ///
-/// With the appropriate extern crate and use declarations (which include
-/// using the Ensure trait from this module):
+/// With the appropriate extern crate and use declarations
 ///
 /// ```ignore
-/// #[macro_use]
 /// extern crate xpcom;
-/// use xpcom::Ensure;
+/// use xpcom::xpcom_method;
 /// ```
 ///
 /// Invoking the macro with the name of the XPCOM method, the name of its
 /// Rustic implementation, the set of its arguments, and its return value:
 ///
 /// ```ignore
 /// impl FooBarBaz {
-///   xpcom_method(Foo, foo, { bar: *const nsACString, baz: bool }, *mut *const nsIVariant);
 ///   xpcom_method!(
 ///       foo => Foo(bar: *const nsACString, baz: bool) -> *const nsIVariant
 ///   );
 /// }
 /// ```
 ///
 /// Results in the macro generating an XPCOM stub like the following:
 ///
 /// ```ignore
 /// unsafe fn Foo(&self, bar: *const nsACString, baz: bool, retval: *mut *const nsIVariant) -> nsresult {
-///     ensure_param!(bar);
-///     ensure_param!(baz);
+///     let bar = match Ensure::ensure(bar) {
+///         Ok(val) => val,
+///         Err(result) => return result,
+///     };
+///     let baz = match Ensure::ensure(baz) {
+///         Ok(val) => val,
+///         Err(result) => return result,
+///     };
 ///
 ///     match self.foo(bar, baz) {
 ///         Ok(val) => {
 ///             val.forget(&mut *retval);
 ///             NS_OK
 ///         }
 ///         Err(error) => {
 ///             error!("{}", error);
@@ -89,27 +92,50 @@ use nserror::{nsresult, NS_ERROR_NULL_PO
 ///
 /// This macro assumes that all non-null pointer arguments are valid!
 /// It does ensure that they aren't null, using the `ensure_param` macro.
 /// But it doesn't otherwise check their validity. That makes the function
 /// unsafe, so callers must ensure that they only call it with valid pointer
 /// arguments.
 #[macro_export]
 macro_rules! xpcom_method {
+    // This rule is provided to ensure external modules don't need to import
+    // internal implementation details of xpcom_method.
+    // The @ensure_param rule converts raw pointer arguments to references,
+    // returning NS_ERROR_NULL_POINTER if the argument is_null().
+    //
+    // Notes:
+    //
+    // This rule can be called on a non-pointer copy parameter, but there's no
+    // benefit to doing so.  The macro will just set the value of the parameter
+    // to itself. (This macro does this anyway due to limitations in declarative
+    // macros; it isn't currently possible to distinguish between pointer and
+    // copy types when processing a set of parameters.)
+    //
+    // The macro currently supports only in-parameters (*const nsIFoo); It
+    // doesn't (yet?) support out-parameters (*mut nsIFoo).  The xpcom_method
+    // macro itself does, however, support the return value out-parameter.
+    (@ensure_param $name:ident) => {
+        let $name = match $crate::Ensure::ensure($name) {
+            Ok(val) => val,
+            Err(result) => return result,
+        };
+    };
+
     // `#[allow(non_snake_case)]` is used for each method because `$xpcom_name`
     // is almost always UpperCamelCase, and Rust gives a warning that it should
     // be snake_case. It isn't reasonable to rename the XPCOM methods, so
     // silence the warning.
 
     // A method whose return value is a *mut *const nsISomething type.
     // Example: foo => Foo(bar: *const nsACString, baz: bool) -> *const nsIVariant
     ($rust_name:ident => $xpcom_name:ident($($param_name:ident: $param_type:ty),*) -> *const $retval:ty) => {
         #[allow(non_snake_case)]
         unsafe fn $xpcom_name(&self, $($param_name: $param_type,)* retval: *mut *const $retval) -> nsresult {
-            $(ensure_param!($param_name);)*
+            $(xpcom_method!(@ensure_param $param_name);)*
             match self.$rust_name($($param_name, )*) {
                 Ok(val) => {
                     val.forget(&mut *retval);
                     NS_OK
                 }
                 Err(error) => {
                     error.into()
                 }
@@ -117,17 +143,17 @@ macro_rules! xpcom_method {
         }
     };
 
     // A method whose return value is a *mut nsAString type.
     // Example: foo => Foo(bar: *const nsACString, baz: bool) -> nsAString
     ($rust_name:ident => $xpcom_name:ident($($param_name:ident: $param_type:ty),*) -> nsAString) => {
         #[allow(non_snake_case)]
         unsafe fn $xpcom_name(&self, $($param_name: $param_type,)* retval: *mut nsAString) -> nsresult {
-            $(ensure_param!($param_name);)*
+            $(xpcom_method!(@ensure_param $param_name);)*
             match self.$rust_name($($param_name, )*) {
                 Ok(val) => {
                     (*retval).assign(&val);
                     NS_OK
                 }
                 Err(error) => {
                     error.into()
                 }
@@ -135,17 +161,17 @@ macro_rules! xpcom_method {
         }
     };
 
     // A method whose return value is a *mut nsACString type.
     // Example: foo => Foo(bar: *const nsACString, baz: bool) -> nsACString
     ($rust_name:ident => $xpcom_name:ident($($param_name:ident: $param_type:ty),*) -> nsACString) => {
         #[allow(non_snake_case)]
         unsafe fn $xpcom_name(&self, $($param_name: $param_type,)* retval: *mut nsACString) -> nsresult {
-            $(ensure_param!($param_name);)*
+            $(xpcom_method!(@ensure_param $param_name);)*
             match self.$rust_name($($param_name, )*) {
                 Ok(val) => {
                     (*retval).assign(&val);
                     NS_OK
                 }
                 Err(error) => {
                     error.into()
                 }
@@ -153,17 +179,17 @@ macro_rules! xpcom_method {
         }
     };
 
     // A method whose return value is a non-nsA[C]String *mut type.
     // Example: foo => Foo(bar: *const nsACString, baz: bool) -> bool
     ($rust_name:ident => $xpcom_name:ident($($param_name:ident: $param_type:ty),*) -> $retval:ty) => {
         #[allow(non_snake_case)]
         unsafe fn $xpcom_name(&self, $($param_name: $param_type,)* retval: *mut $retval) -> nsresult {
-            $(ensure_param!($param_name);)*
+            $(xpcom_method!(@ensure_param $param_name);)*
             match self.$rust_name($($param_name, )*) {
                 Ok(val) => {
                     *retval = val;
                     NS_OK
                 }
                 Err(error) => {
                     error.into()
                 }
@@ -171,103 +197,31 @@ macro_rules! xpcom_method {
         }
     };
 
     // A method that doesn't have a return value.
     // Example: foo => Foo(bar: *const nsACString, baz: bool)
     ($rust_name:ident => $xpcom_name:ident($($param_name:ident: $param_type:ty),*)) => {
         #[allow(non_snake_case)]
         unsafe fn $xpcom_name(&self, $($param_name: $param_type,)*) -> nsresult {
-            $(ensure_param!($param_name);)*
+            $(xpcom_method!(@ensure_param $param_name);)*
             match self.$rust_name($($param_name, )*) {
                 Ok(_) => NS_OK,
                 Err(error) => {
                     error.into()
                 }
             }
         }
     };
 }
 
-/// The ensure_param macro converts raw pointer arguments to references, and
-/// passes them to a Rustic implementation of an XPCOM method. This macro isn't
-/// intended to be used directly but rather via the xpcom_method macro.
-///
-/// If the argument `is_null()`, and the corresponding Rustic method parameter
-/// is `&T`, the macro returns `NS_ERROR_NULL_POINTER`. However, if the
-/// parameter is `Option<&T>`, the macro passes `None` instead. This makes it
-/// easy to use optional arguments safely.
-///
-/// Given the appropriate extern crate and use declarations (which include
-/// using the Ensure trait from this module):
-///
-/// ```ignore
-/// #[macro_use]
-/// extern crate xpcom;
-/// use xpcom::Ensure;
-/// ```
-///
-/// Invoking the macro like this:
-///
-/// ```ignore
-/// fn do_something_with_foo(foo: &nsIBar) {}
-/// fn DoSomethingWithFoo(foo: *const nsIBar) -> nsresult {
-///     let foo = ensure_param!(foo);
-///     do_something_with_foo(foo);
-/// }
-/// ```
-///
-/// Expands to code like this:
-///
-/// ```ignore
-/// fn do_something_with_foo(foo: &nsIBar) {}
-/// fn DoSomethingWithFoo(foo: *const nsIBar) -> nsresult {
-///     let foo = match Ensure::ensure(foo) {
-///         Ok(val) => val,
-///         Err(result) => return result,
-///     };
-///     do_something_with_foo(foo);
-/// }
-/// ```
-///
-/// Which converts `foo` from a `*const nsIBar` to a `&nsIBar`, or returns
-/// `NS_ERROR_NULL_POINTER` if `foo` is null.
-///
-/// To pass an optional argument, we only need to change
-/// `do_something_with_foo` to take an `Option<&nsIBar> instead. The macro
-/// generates the same code, but `do_something_with_foo` receives `None` if
-/// `foo` is null.
-///
-/// Notes:
-///
-/// You can call the macro on a non-pointer copy parameter, but there's no
-/// benefit to doing so.  The macro will just set the value of the parameter
-/// to itself.  (The xpcom_method macro does this anyway due to limitations
-/// in declarative macros; it isn't currently possible to distinguish between
-/// pointer and copy types when processing a set of parameters.)
-///
-/// The macro currently supports only inparameters (*const nsIFoo); It doesn't
-/// (yet?) support outparameters (*mut nsIFoo).  The xpcom_method macro itself
-/// does, however, support the return value outparameter.
-///
-#[doc(hidden)]
-#[macro_export]
-macro_rules! ensure_param {
-    ($name:ident) => {
-        let $name = match $crate::Ensure::ensure($name) {
-            Ok(val) => val,
-            Err(result) => return result,
-        };
-    };
-}
-
 /// A trait that ensures that a raw pointer isn't null and converts it to
-/// a reference.  Because of limitations in declarative macros (see the docs
-/// for the ensure_param macro), this includes an implementation for types
-/// that are Copy, which simply returns the value itself.
+/// a reference.  Because of limitations in declarative macros, this includes an
+/// implementation for types that are Copy, which simply returns the value
+/// itself.
 #[doc(hidden)]
 pub trait Ensure<T> {
     unsafe fn ensure(T) -> Self;
 }
 
 impl<'a, T: 'a> Ensure<*const T> for Result<&'a T, nsresult> {
     unsafe fn ensure(ptr: *const T) -> Result<&'a T, nsresult> {
         if ptr.is_null() {