async_utils/hanging_get/
error.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::format_err;
6use futures::channel::{mpsc, oneshot};
7use thiserror::Error;
8
9/// Error types that may be used by the async hanging-get server.
10#[derive(Error, Debug)]
11pub enum HangingGetServerError {
12    /// An existing observer was already present for the client.
13    #[error("Cannot have multiple concurrent observers for a single client")]
14    MultipleObservers,
15
16    /// The HangingGetBroker associated with this handle has been dropped.
17    #[error("The HangingGetBroker associated with this handle has been dropped.")]
18    NoBroker,
19
20    /// This handle is sending messages faster than the broker can process them.
21    #[error("This handle is sending messages faster than the broker can process them.")]
22    RateLimit,
23
24    /// Generic hanging-get server error.
25    #[error("Error: {}", .0)]
26    Generic(anyhow::Error),
27}
28
29impl PartialEq for HangingGetServerError {
30    fn eq(&self, other: &Self) -> bool {
31        use HangingGetServerError::*;
32        match (self, other) {
33            (MultipleObservers, MultipleObservers)
34            | (NoBroker, NoBroker)
35            | (RateLimit, RateLimit) => true,
36            _ => false,
37        }
38    }
39}
40
41impl From<mpsc::SendError> for HangingGetServerError {
42    fn from(error: mpsc::SendError) -> Self {
43        if error.is_disconnected() {
44            HangingGetServerError::NoBroker
45        } else if error.is_full() {
46            HangingGetServerError::RateLimit
47        } else {
48            HangingGetServerError::Generic(format_err!(
49                "Unknown SendError error condition: {}",
50                error
51            ))
52        }
53    }
54}
55
56impl From<oneshot::Canceled> for HangingGetServerError {
57    fn from(e: oneshot::Canceled) -> Self {
58        HangingGetServerError::Generic(e.into())
59    }
60}
61
62impl From<anyhow::Error> for HangingGetServerError {
63    /// Try downcasting to more specific error types, falling back to `Generic` if that fails.
64    fn from(e: anyhow::Error) -> Self {
65        e.downcast::<mpsc::SendError>().map_or_else(HangingGetServerError::Generic, Self::from)
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn error_partial_eq_impl() {
75        use HangingGetServerError::*;
76        let variants = [MultipleObservers, NoBroker, RateLimit, Generic(format_err!("err"))];
77        for (i, a) in variants.iter().enumerate() {
78            for (j, b) in variants.iter().enumerate() {
79                // variants with the same index are equal except `Generic` errors are _never_ equal.
80                if i == j && i != 3 && j != 3 {
81                    assert_eq!(a, b);
82                } else {
83                    assert_ne!(a, b);
84                }
85            }
86        }
87    }
88}