diff options
Diffstat (limited to 'toolkit/components/bitsdownload/src/bits_interface/xpcom_methods.rs')
-rw-r--r-- | toolkit/components/bitsdownload/src/bits_interface/xpcom_methods.rs | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/toolkit/components/bitsdownload/src/bits_interface/xpcom_methods.rs b/toolkit/components/bitsdownload/src/bits_interface/xpcom_methods.rs new file mode 100644 index 0000000000..cb267b9634 --- /dev/null +++ b/toolkit/components/bitsdownload/src/bits_interface/xpcom_methods.rs @@ -0,0 +1,195 @@ +/* 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 macro is very similar to xpcom_macro, but works a bit differently: +/// +/// When possible, it returns errors via the callback rather than via the return +/// value. +/// +/// It implicitly adds the callback argument of type: nsIBitsNewRequestCallback +/// +/// It needs an action type, to be specified before the rust name, in square +/// brackets. +/// +/// The rustic implementation that the xpcom method calls is expected to return +/// the type: Result<_, BitsTaskError>. If this value is Ok, it will be ignored. +/// If the value is Err, it will be returned via the callback passed. +/// +/// Usage like this: +/// +/// ```ignore +/// nsIBits_method!( +/// [ActionType] +/// rust_method => XpcomMethod( +/// foo: *const nsACString, +/// bar: *const nsIBar, +/// baz: bool, +/// [optional] qux: *const nsIQux, +/// ) +/// ); +/// ``` +/// +/// Results in the macro generating a method like: +/// +/// ```ignore +/// unsafe fn XpcomMethod( +/// &self, +/// foo: *const nsACString, +/// bar: *const nsIBar, +/// baz: bool, +/// qux: *const nsIQux, +/// callback: *const nsIBitsNewRequestCallback, +/// ) -> nsresult { +/// let callback: &nsIBitsNewRequestCallback = match xpcom::Ensure::ensure(callback) { +/// Ok(val) => val, +/// Err(result) => return result, +/// }; +/// let foo = match xpcom::Ensure::ensure(foo) { +/// Ok(val) => val, +/// Err(_) => { +/// dispatch_pretask_interface_error(BitsTaskError::new(ErrorType::NullArgument, ActionType.into(), ErrorStage::Pretask), callback); +/// return NS_OK; +/// } +/// }; +/// let bar = match xpcom::Ensure::ensure(bar) { +/// Ok(val) => val, +/// Err(_) => { +/// dispatch_pretask_interface_error(BitsTaskError::new(ErrorType::NullArgument, ActionType.into(), ErrorStage::Pretask), callback); +/// return NS_OK; +/// } +/// }; +/// let baz = match xpcom::Ensure::ensure(baz) { +/// Ok(val) => val, +/// Err(_) => { +/// dispatch_pretask_interface_error(BitsTaskError::new(ErrorType::NullArgument, ActionType.into(), ErrorStage::Pretask), callback); +/// return NS_OK; +/// } +/// }; +/// let qux = match xpcom::Ensure::ensure(qux) { +/// Ok(val) => Some(val), +/// Err(_) => None, +/// }; +/// +/// if let Err(error) = self.rust_method(foo, bar, baz, qux, callback) { +/// dispatch_pretask_interface_error(error, callback); +/// } +/// +/// NS_OK +/// } +/// ``` +/// +/// Which expects a Rustic implementation method like: +/// +/// ```ignore +/// fn rust_method( +/// &self, +/// foo: &nsACString, +/// bar: &nsIBar, +/// baz: bool, +/// qux: Option<&nsIQux>, +/// callback: &nsIBitsNewRequestCallback, +/// ) -> Result<(), BitsTaskError> { +/// do_something() +/// } +/// ``` +#[macro_export] +macro_rules! nsIBits_method { + // The internal rule @ensure_param converts raw pointer arguments to + // references, calling dispatch_pretask_interface_error and returning if the + // argument is null. + // If, however, the type is optional, the reference will also be wrapped + // in an option and null pointers will be converted to None. + (@ensure_param [optional] $name:ident, $action:expr, $callback:ident) => { + let $name = match Ensure::ensure($name) { + Ok(val) => Some(val), + Err(_) => None, + }; + }; + (@ensure_param $name:ident, $action:expr, $callback:ident) => { + let $name = match Ensure::ensure($name) { + Ok(val) => val, + Err(_) => { + dispatch_pretask_interface_error(BitsTaskError::new(NullArgument, $action.into(), Pretask), $callback); + return NS_OK; + } + }; + }; + + ([$action:expr] $rust_name:ident => $xpcom_name:ident($($([$param_required:ident])* $param_name:ident: $param_type:ty $(,)*)*)) => { + #[allow(non_snake_case)] + unsafe fn $xpcom_name(&self, $($param_name: $param_type, )* callback: *const nsIBitsNewRequestCallback) -> nsresult { + use xpcom::Ensure; + use nserror::NS_OK; + // When no params are passed, the imports below will not be used, so silence the + // warning + #[allow(unused_imports)] + use bits_interface::{ + dispatch_callback::dispatch_pretask_interface_error, + error::{BitsTaskError, ErrorStage::Pretask, ErrorType::NullArgument}, + }; + + let callback: &nsIBitsNewRequestCallback = match Ensure::ensure(callback) { + Ok(val) => val, + Err(result) => return result, + }; + $(nsIBits_method!(@ensure_param $([$param_required])* $param_name, $action, callback);)* + if let Err(error) = self.$rust_name($($param_name, )* callback) { + dispatch_pretask_interface_error(error, callback); + } + NS_OK + } + }; +} + +/* + * Same as above, but expects a nsIBitsCallback as its callback. + */ +#[macro_export] +macro_rules! nsIBitsRequest_method { + // The internal rule @ensure_param converts raw pointer arguments to + // references, calling dispatch_pretask_interface_error and returning if the + // argument is null. + // If, however, the type is optional, the reference will also be wrapped + // in an option and null pointers will be converted to None. + (@ensure_param [optional] $name:ident, $action:expr, $callback:ident) => { + let $name = match Ensure::ensure($name) { + Ok(val) => Some(val), + Err(_) => None, + }; + }; + (@ensure_param $name:ident, $action:expr, $callback:ident) => { + let $name = match Ensure::ensure($name) { + Ok(val) => val, + Err(_) => { + dispatch_pretask_request_error(BitsTaskError::new(NullArgument, $action.into(), Pretask), $callback); + return NS_OK; + } + }; + }; + + ([$action:expr] $rust_name:ident => $xpcom_name:ident($($([$param_required:ident])* $param_name:ident: $param_type:ty $(,)*)*)) => { + #[allow(non_snake_case)] + unsafe fn $xpcom_name(&self, $($param_name: $param_type, )* callback: *const nsIBitsCallback) -> nsresult { + use xpcom::Ensure; + use nserror::NS_OK; + // When no params are passed, the imports below will not be used, so silence the + // warning + #[allow(unused_imports)] + use bits_interface::{ + dispatch_callback::dispatch_pretask_request_error, + error::{BitsTaskError, ErrorStage::Pretask, ErrorType::NullArgument}, + }; + + let callback: &nsIBitsCallback = match Ensure::ensure(callback) { + Ok(val) => val, + Err(result) => return result, + }; + $(nsIBitsRequest_method!(@ensure_param $([$param_required])* $param_name, $action, callback);)* + if let Err(error) = self.$rust_name($($param_name, )* callback) { + dispatch_pretask_request_error(error, callback); + } + NS_OK + } + }; +} |