Repository: servo/servo
File: components/servo/responders.rs (Rust)

Code before:
}

impl<T: Serialize> Drop for IpcResponder<T> {
    fn drop(&mut self) {
        if !self.response_sent {
            let response = self
                .default_response
                .take()
                .expect("Guaranteed by inherent impl");
            // Don’t notify embedder about send errors for the default response,
            // since they didn’t send anything and probably don’t care.
            let _ = self.response_sender.send(response);
        }
    }
}

/// A provider responsible for managing all interactions with gamepads.
#[cfg(feature = "gamepad")]
pub trait GamepadProvider {
    /// Request to play a haptic effect on a connected gamepad.
    fn play_haptic_effect(
        &self,
        _webview: WebView,
        _gamepad_index: usize,
        _effect_type: GamepadHapticEffectType,
        _responder: IpcResponder<bool>,
    ) {
    }

    /// Request to stop a haptic effect on a connected gamepad.
    fn stop_haptic_effect(
        &self,
        _webview: WebView,
        _gamepad_index: usize,
        _responder: IpcResponder<bool>,
    ) {
    }
}

#[cfg(feature = "gamepad")]
pub(crate) struct DefaultGamepadProvider;

#[cfg(feature = "gamepad")]
impl GamepadProvider for DefaultGamepadProvider {}


Review comment (bug):
Let's expose a new type:

```rust
enum GamePadHapticEffectRequestType {
    Start,
    Stop,
}

struct GamepadHapticEffectRequest {
   ...
}

impl GamepadHapticEffectRequest {
    pub fn request_type(&self) ->  GamepadHapticEffectRequest { ... }
    pub fn gamepad_index(&self) ->  usize { ... }
    pub fn effect_type(&self) ->  GamepadHapticEffectRequestType { ... }
    pub fn failed(self) { /* will return false on private responder */ }
    pub fn suceeded(self) { /* will return true on private responder */ }
}
```

Code after:

impl<T> AbstractSender for OneshotSender<T> {
    type Message = T;
    fn send(&self, value: T) -> SendResult {
        let sender = self.0.borrow_mut().take();
        if let Some(sender) = sender {
            TokioOneshotSender::send(sender, value).map_err(|_| SendError::Disconnected)
        } else {
            Err(SendError::Disconnected)
        }
    }
}

/// Sends a response over an IPC channel, or a default response on [`Drop`] if no response was sent.
pub(crate) struct IpcResponder<T> {
    response_sender: Box<dyn AbstractSender<Message = T>>,
    response_sent: bool,
    /// Always present, except when taken by [`Drop`].
    default_response: Option<T>,
}

impl<T: Serialize + 'static> IpcResponder<T> {
    pub(crate) fn new(response_sender: GenericSender<T>, default_response: T) -> Self {
        Self {
            response_sender: Box::new(response_sender),
            response_sent: false,
            default_response: Some(default_response),
        }
    }
}

impl<T: 'static> IpcResponder<T> {
    pub(crate) fn new_same_process(
        response_sender: Box<dyn AbstractSender<Message = T>>,
        default_response: T,
    ) -> Self {
        Self {
            response_sender,
            response_sent: false,
            default_response: Some(default_response),
        }
    }
}

impl<T> IpcResponder<T> {
    pub(crate) fn send(&mut self, response: T) -> SendResult {
        let result = self.response_sender.send(response);
        self.response_sent = true;
        result
    }
}