fix(web): improve make_bridge! macro hygiene (#777)

There was still some room for improvement.
This commit is contained in:
Benoît Cortier 2025-04-23 20:19:23 +02:00 committed by GitHub
parent 24e64d7589
commit 194ed07630
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 131 additions and 59 deletions

View file

@ -4,12 +4,20 @@ pub trait ClipboardData {
type Item: ClipboardItem;
fn create() -> Self;
fn add_text(&mut self, mime_type: &str, text: &str);
fn add_binary(&mut self, mime_type: &str, binary: &[u8]);
fn items(&self) -> &[Self::Item];
fn is_empty(&self) -> bool {
self.items().is_empty()
}
}
pub trait ClipboardItem {
fn mime_type(&self) -> &str;
fn value(&self) -> impl Into<JsValue>;
}

View file

@ -2,6 +2,7 @@ use wasm_bindgen::prelude::*;
pub trait IronError {
fn backtrace(&self) -> String;
fn kind(&self) -> IronErrorKind;
}

View file

@ -1,11 +1,18 @@
pub trait DeviceEvent {
fn mouse_button_pressed(button: u8) -> Self;
fn mouse_button_released(button: u8) -> Self;
fn mouse_move(x: u16, y: u16) -> Self;
fn wheel_rotations(vertical: bool, rotation_units: i16) -> Self;
fn key_pressed(scancode: u16) -> Self;
fn key_released(scancode: u16) -> Self;
fn unicode_pressed(unicode: char) -> Self;
fn unicode_released(unicode: char) -> Self;
}
@ -13,5 +20,6 @@ pub trait InputTransaction {
type DeviceEvent: DeviceEvent;
fn create() -> Self;
fn add_event(&mut self, event: Self::DeviceEvent);
}

View file

@ -37,11 +37,6 @@ pub trait RemoteDesktopApi {
#[macro_export]
macro_rules! make_bridge {
($api:ty) => {
use $crate::{
ClipboardData as _, ClipboardItem as _, DeviceEvent as _, InputTransaction as _, IronError as _,
Session as _, SessionBuilder as _, SessionTerminationInfo as _,
};
#[$crate::internal::wasm_bindgen::prelude::wasm_bindgen]
pub struct Session(<$api as $crate::RemoteDesktopApi>::Session);
@ -126,22 +121,25 @@ macro_rules! make_bridge {
#[doc(hidden)]
impl Session {
pub async fn run(&self) -> Result<SessionTerminationInfo, IronError> {
self.0.run().await.map(SessionTerminationInfo).map_err(IronError)
$crate::Session::run(&self.0)
.await
.map(SessionTerminationInfo)
.map_err(IronError)
}
#[wasm_bindgen(js_name = desktopSize)]
pub fn desktop_size(&self) -> $crate::DesktopSize {
self.0.desktop_size()
$crate::Session::desktop_size(&self.0)
}
#[wasm_bindgen(js_name = applyInputs)]
pub fn apply_inputs(&self, transaction: InputTransaction) -> Result<(), IronError> {
self.0.apply_inputs(transaction.0).map_err(IronError)
$crate::Session::apply_inputs(&self.0, transaction.0).map_err(IronError)
}
#[wasm_bindgen(js_name = releaseAllInputs)]
pub fn release_all_inputs(&self) -> Result<(), IronError> {
self.0.release_all_inputs().map_err(IronError)
$crate::Session::release_all_inputs(&self.0).map_err(IronError)
}
#[wasm_bindgen(js_name = synchronizeLockKeys)]
@ -152,18 +150,19 @@ macro_rules! make_bridge {
caps_lock: bool,
kana_lock: bool,
) -> Result<(), IronError> {
self.0
.synchronize_lock_keys(scroll_lock, num_lock, caps_lock, kana_lock)
$crate::Session::synchronize_lock_keys(&self.0, scroll_lock, num_lock, caps_lock, kana_lock)
.map_err(IronError)
}
pub fn shutdown(&self) -> Result<(), IronError> {
self.0.shutdown().map_err(IronError)
$crate::Session::shutdown(&self.0).map_err(IronError)
}
#[wasm_bindgen(js_name = onClipboardPaste)]
pub async fn on_clipboard_paste(&self, content: ClipboardData) -> Result<(), IronError> {
self.0.on_clipboard_paste(content.0).await.map_err(IronError)
$crate::Session::on_clipboard_paste(&self.0, content.0)
.await
.map_err(IronError)
}
pub fn resize(
@ -174,20 +173,26 @@ macro_rules! make_bridge {
physical_width: Option<u32>,
physical_height: Option<u32>,
) {
self.0
.resize(width, height, scale_factor, physical_width, physical_height);
$crate::Session::resize(
&self.0,
width,
height,
scale_factor,
physical_width,
physical_height,
);
}
#[wasm_bindgen(js_name = supportsUnicodeKeyboardShortcuts)]
pub fn supports_unicode_keyboard_shortcuts(&self) -> bool {
self.0.supports_unicode_keyboard_shortcuts()
$crate::Session::supports_unicode_keyboard_shortcuts(&self.0)
}
#[wasm_bindgen(js_name = extensionCall)]
pub fn extension_call(
ext: $crate::Extension,
) -> Result<$crate::internal::wasm_bindgen::JsValue, IronError> {
<<$api as $crate::RemoteDesktopApi>::Session>::extension_call(ext).map_err(IronError)
<<$api as $crate::RemoteDesktopApi>::Session as $crate::Session>::extension_call(ext).map_err(IronError)
}
}
@ -196,54 +201,58 @@ macro_rules! make_bridge {
impl SessionBuilder {
#[wasm_bindgen(constructor)]
pub fn create() -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::SessionBuilder>::create())
Self(<<$api as $crate::RemoteDesktopApi>::SessionBuilder as $crate::SessionBuilder>::create())
}
pub fn username(&self, username: String) -> Self {
Self(self.0.username(username))
Self($crate::SessionBuilder::username(&self.0, username))
}
pub fn destination(&self, destination: String) -> Self {
Self(self.0.destination(destination))
Self($crate::SessionBuilder::destination(&self.0, destination))
}
#[wasm_bindgen(js_name = serverDomain)]
pub fn server_domain(&self, server_domain: String) -> Self {
Self(self.0.server_domain(server_domain))
Self($crate::SessionBuilder::server_domain(&self.0, server_domain))
}
pub fn password(&self, password: String) -> Self {
Self(self.0.password(password))
Self($crate::SessionBuilder::password(&self.0, password))
}
#[wasm_bindgen(js_name = proxyAddress)]
pub fn proxy_address(&self, address: String) -> Self {
Self(self.0.proxy_address(address))
Self($crate::SessionBuilder::proxy_address(&self.0, address))
}
#[wasm_bindgen(js_name = authToken)]
pub fn auth_token(&self, token: String) -> Self {
Self(self.0.auth_token(token))
Self($crate::SessionBuilder::auth_token(&self.0, token))
}
#[wasm_bindgen(js_name = desktopSize)]
pub fn desktop_size(&self, desktop_size: $crate::DesktopSize) -> Self {
Self(self.0.desktop_size(desktop_size))
Self($crate::SessionBuilder::desktop_size(&self.0, desktop_size))
}
#[wasm_bindgen(js_name = renderCanvas)]
pub fn render_canvas(&self, canvas: $crate::internal::web_sys::HtmlCanvasElement) -> Self {
Self(self.0.render_canvas(canvas))
Self($crate::SessionBuilder::render_canvas(&self.0, canvas))
}
#[wasm_bindgen(js_name = setCursorStyleCallback)]
pub fn set_cursor_style_callback(&self, callback: $crate::internal::web_sys::js_sys::Function) -> Self {
Self(self.0.set_cursor_style_callback(callback))
Self($crate::SessionBuilder::set_cursor_style_callback(
&self.0, callback,
))
}
#[wasm_bindgen(js_name = setCursorStyleCallbackContext)]
pub fn set_cursor_style_callback_context(&self, context: $crate::internal::wasm_bindgen::JsValue) -> Self {
Self(self.0.set_cursor_style_callback_context(context))
Self($crate::SessionBuilder::set_cursor_style_callback_context(
&self.0, context,
))
}
#[wasm_bindgen(js_name = remoteClipboardChangedCallback)]
@ -251,7 +260,9 @@ macro_rules! make_bridge {
&self,
callback: $crate::internal::web_sys::js_sys::Function,
) -> Self {
Self(self.0.remote_clipboard_changed_callback(callback))
Self($crate::SessionBuilder::remote_clipboard_changed_callback(
&self.0, callback,
))
}
#[wasm_bindgen(js_name = remoteReceivedFormatListCallback)]
@ -259,7 +270,9 @@ macro_rules! make_bridge {
&self,
callback: $crate::internal::web_sys::js_sys::Function,
) -> Self {
Self(self.0.remote_received_format_list_callback(callback))
Self($crate::SessionBuilder::remote_received_format_list_callback(
&self.0, callback,
))
}
#[wasm_bindgen(js_name = forceClipboardUpdateCallback)]
@ -267,15 +280,20 @@ macro_rules! make_bridge {
&self,
callback: $crate::internal::web_sys::js_sys::Function,
) -> Self {
Self(self.0.force_clipboard_update_callback(callback))
Self($crate::SessionBuilder::force_clipboard_update_callback(
&self.0, callback,
))
}
pub fn extension(&self, ext: $crate::Extension) -> Self {
Self(self.0.extension(ext))
Self($crate::SessionBuilder::extension(&self.0, ext))
}
pub async fn connect(&self) -> Result<Session, IronError> {
self.0.connect().await.map(Session).map_err(IronError)
$crate::SessionBuilder::connect(&self.0)
.await
.map(Session)
.map_err(IronError)
}
}
@ -283,7 +301,7 @@ macro_rules! make_bridge {
#[doc(hidden)]
impl SessionTerminationInfo {
pub fn reason(&self) -> String {
self.0.reason()
$crate::SessionTerminationInfo::reason(&self.0)
}
}
@ -292,48 +310,57 @@ macro_rules! make_bridge {
impl DeviceEvent {
#[wasm_bindgen(js_name = mouseButtonPressed)]
pub fn mouse_button_pressed(button: u8) -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent>::mouse_button_pressed(button))
Self(
<<$api as $crate::RemoteDesktopApi>::DeviceEvent as $crate::DeviceEvent>::mouse_button_pressed(
button,
),
)
}
#[wasm_bindgen(js_name = mouseButtonReleased)]
pub fn mouse_button_released(button: u8) -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent>::mouse_button_released(button))
Self(
<<$api as $crate::RemoteDesktopApi>::DeviceEvent as $crate::DeviceEvent>::mouse_button_released(
button,
),
)
}
#[wasm_bindgen(js_name = mouseMove)]
pub fn mouse_move(x: u16, y: u16) -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent>::mouse_move(
x, y,
))
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent as $crate::DeviceEvent>::mouse_move(x, y))
}
#[wasm_bindgen(js_name = wheelRotations)]
pub fn wheel_rotations(vertical: bool, rotation_units: i16) -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent>::wheel_rotations(vertical, rotation_units))
Self(
<<$api as $crate::RemoteDesktopApi>::DeviceEvent as $crate::DeviceEvent>::wheel_rotations(
vertical,
rotation_units,
),
)
}
#[wasm_bindgen(js_name = keyPressed)]
pub fn key_pressed(scancode: u16) -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent>::key_pressed(
scancode,
))
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent as $crate::DeviceEvent>::key_pressed(scancode))
}
#[wasm_bindgen(js_name = keyReleased)]
pub fn key_released(scancode: u16) -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent>::key_released(
scancode,
))
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent as $crate::DeviceEvent>::key_released(scancode))
}
#[wasm_bindgen(js_name = unicodePressed)]
pub fn unicode_pressed(unicode: char) -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent>::unicode_pressed(unicode))
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent as $crate::DeviceEvent>::unicode_pressed(unicode))
}
#[wasm_bindgen(js_name = unicodeReleased)]
pub fn unicode_released(unicode: char) -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::DeviceEvent>::unicode_released(unicode))
Self(
<<$api as $crate::RemoteDesktopApi>::DeviceEvent as $crate::DeviceEvent>::unicode_released(unicode),
)
}
}
@ -342,12 +369,12 @@ macro_rules! make_bridge {
impl InputTransaction {
#[wasm_bindgen(constructor)]
pub fn create() -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::InputTransaction>::create())
Self(<<$api as $crate::RemoteDesktopApi>::InputTransaction as $crate::InputTransaction>::create())
}
#[wasm_bindgen(js_name = addEvent)]
pub fn add_event(&mut self, event: DeviceEvent) {
self.0.add_event(event.0);
$crate::InputTransaction::add_event(&mut self.0, event.0);
}
}
@ -356,26 +383,30 @@ macro_rules! make_bridge {
impl ClipboardData {
#[wasm_bindgen(constructor)]
pub fn create() -> Self {
Self(<<$api as $crate::RemoteDesktopApi>::ClipboardData>::create())
Self(<<$api as $crate::RemoteDesktopApi>::ClipboardData as $crate::ClipboardData>::create())
}
#[wasm_bindgen(js_name = addText)]
pub fn add_text(&mut self, mime_type: &str, text: &str) {
self.0.add_text(mime_type, text);
$crate::ClipboardData::add_text(&mut self.0, mime_type, text);
}
#[wasm_bindgen(js_name = addBinary)]
pub fn add_binary(&mut self, mime_type: &str, binary: &[u8]) {
self.0.add_binary(mime_type, binary);
$crate::ClipboardData::add_binary(&mut self.0, mime_type, binary);
}
pub fn items(&self) -> Vec<ClipboardItem> {
self.0.items().into_iter().cloned().map(ClipboardItem).collect()
$crate::ClipboardData::items(&self.0)
.into_iter()
.cloned()
.map(ClipboardItem)
.collect()
}
#[wasm_bindgen(js_name = isEmpty)]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
$crate::ClipboardData::is_empty(&self.0)
}
}
@ -384,11 +415,11 @@ macro_rules! make_bridge {
impl ClipboardItem {
#[wasm_bindgen(js_name = mimeType)]
pub fn mime_type(&self) -> String {
self.0.mime_type().to_owned()
$crate::ClipboardItem::mime_type(&self.0).to_owned()
}
pub fn value(&self) -> $crate::internal::wasm_bindgen::JsValue {
self.0.value().into()
$crate::ClipboardItem::value(&self.0).into()
}
}
@ -396,11 +427,11 @@ macro_rules! make_bridge {
#[doc(hidden)]
impl IronError {
pub fn backtrace(&self) -> String {
self.0.backtrace()
$crate::IronError::backtrace(&self.0)
}
pub fn kind(&self) -> $crate::IronErrorKind {
self.0.kind()
$crate::IronError::kind(&self.0)
}
}
};

View file

@ -11,34 +11,49 @@ pub trait SessionBuilder {
type Error: IronError;
fn create() -> Self;
#[must_use]
fn username(&self, username: String) -> Self;
#[must_use]
fn destination(&self, destination: String) -> Self;
#[must_use]
fn server_domain(&self, server_domain: String) -> Self;
#[must_use]
fn password(&self, password: String) -> Self;
#[must_use]
fn proxy_address(&self, address: String) -> Self;
#[must_use]
fn auth_token(&self, token: String) -> Self;
#[must_use]
fn desktop_size(&self, desktop_size: DesktopSize) -> Self;
#[must_use]
fn render_canvas(&self, canvas: HtmlCanvasElement) -> Self;
#[must_use]
fn set_cursor_style_callback(&self, callback: js_sys::Function) -> Self;
#[must_use]
fn set_cursor_style_callback_context(&self, context: JsValue) -> Self;
#[must_use]
fn remote_clipboard_changed_callback(&self, callback: js_sys::Function) -> Self;
#[must_use]
fn remote_received_format_list_callback(&self, callback: js_sys::Function) -> Self;
#[must_use]
fn force_clipboard_update_callback(&self, callback: js_sys::Function) -> Self;
#[must_use]
fn extension(&self, ext: Extension) -> Self;
#[expect(async_fn_in_trait)]
async fn connect(&self) -> Result<Self::Session, Self::Error>;
}
@ -50,9 +65,13 @@ pub trait Session {
type Error: IronError;
fn run(&self) -> impl core::future::Future<Output = Result<Self::SessionTerminationInfo, Self::Error>>;
fn desktop_size(&self) -> DesktopSize;
fn apply_inputs(&self, transaction: Self::InputTransaction) -> Result<(), Self::Error>;
fn release_all_inputs(&self) -> Result<(), Self::Error>;
fn synchronize_lock_keys(
&self,
scroll_lock: bool,
@ -60,11 +79,14 @@ pub trait Session {
caps_lock: bool,
kana_lock: bool,
) -> Result<(), Self::Error>;
fn shutdown(&self) -> Result<(), Self::Error>;
fn on_clipboard_paste(
&self,
content: Self::ClipboardTransaction,
) -> impl core::future::Future<Output = Result<(), Self::Error>>;
fn resize(
&self,
width: u32,
@ -73,7 +95,9 @@ pub trait Session {
physical_width: Option<u32>,
physical_height: Option<u32>,
);
fn supports_unicode_keyboard_shortcuts(&self) -> bool;
fn extension_call(ext: Extension) -> Result<JsValue, Self::Error>;
}