feat(protocols): Add more control over gathering additional information (#180)

* protocols: Add more control over gathering additional information

Adds GatherToggle which allows choosing the behaviour for how the query
handles fetching additional information. The choices are:
- DontGather - Don't attempt to fetch information
- AttemptGather - Try to fetch the information but ignore errors
- Required - Try to fetch information and fail if it errors

A handy macro was also added to utils to dispatch additional queries
based on a GatherToggle value.

* Add/Update badge

* protocols: Improve GatherToggle enum names

Co-Authored-By: Cain <75994858+cainthebest@users.noreply.github.com>
Co-Authored-By: CosminPerRam <cosmin.p@live.com>

* Add/Update badge

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Cain <75994858+cainthebest@users.noreply.github.com>
Co-authored-by: CosminPerRam <cosmin.p@live.com>
This commit is contained in:
Tom 2024-01-22 11:36:17 +00:00 committed by GitHub
parent 6d0c25d6ea
commit 89ed19f089
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 195 additions and 64 deletions

View file

@ -29,11 +29,62 @@ pub fn retry_on_timeout<T>(mut retry_count: usize, mut fetch: impl FnMut() -> GD
Err(last_err)
}
/// Run gather_fn based on the value of gather_toggle.
///
/// # Parameters
/// - `gather_toggle` should be an expression resolving to a
/// [crate::protocols::types::GatherToggle].
/// - `gather_fn` should be an expression that returns a [crate::GDResult].
///
/// # States
/// - [DontGather](crate::protocols::types::GatherToggle::DontGather) - Don't
/// run gather function, returns None.
/// - [AttemptGather](crate::protocols::types::GatherToggle::AttemptGather) -
/// Runs the gather function, if it returns an error return None, else return
/// Some.
/// - [Required](crate::protocols::types::GatherToggle::Required) - Runs the
/// gather function, if it returns an error propagate it using the `?`
/// operator, else return Some.
///
/// # Examples
///
/// ```ignore,Doctests cannot access private items
/// use gamedig::protocols::types::GatherToggle;
/// use gamedig::utils::maybe_gather;
///
/// let query_fn = || { Err("Query error") };
///
/// // query_fn() is not called
/// let response = maybe_gather!(GatherToggle::DontGather, query_fn());
/// assert!(response.is_none());
///
/// // query_fn() is called but Err is converted to None
/// let response = maybe_gather!(GatherToggle::AttemptGather, query_fn());
/// assert!(response.is_none());
///
/// // query_fn() is called and Err is propagated.
/// let response = maybe_gather!(GatherToggle::Required, query_fn());
/// unreachable!();
/// ```
macro_rules! maybe_gather {
($gather_toggle: expr, $gather_fn: expr) => {
match $gather_toggle {
crate::protocols::types::GatherToggle::Skip => None,
crate::protocols::types::GatherToggle::Try => $gather_fn.ok(),
crate::protocols::types::GatherToggle::Enforce => Some($gather_fn?),
}
};
}
pub(crate) use maybe_gather;
#[cfg(test)]
mod tests {
use super::retry_on_timeout;
use crate::{
GDErrorKind::{PacketBad, PacketReceive, PacketSend},
protocols::types::GatherToggle,
GDError,
GDErrorKind::{self, PacketBad, PacketReceive, PacketSend},
GDResult,
};
@ -105,4 +156,53 @@ mod tests {
assert!(r.is_err());
assert_eq!(r.unwrap_err().kind, PacketBad);
}
fn gather_success(n: i32) -> GDResult<i32> { Ok(n) }
fn gather_fail(err: &'static str) -> GDResult<i32> { Err(GDErrorKind::PacketSend.context(err)) }
#[test]
fn gather_success_dont_gather() -> GDResult<()> {
let result = maybe_gather!(GatherToggle::Skip, gather_success(5));
assert!(result.is_none());
Ok(())
}
#[test]
fn gather_success_attempt_gather() -> GDResult<()> {
let result = maybe_gather!(GatherToggle::Try, gather_success(10));
assert_eq!(result, Some(10));
Ok(())
}
#[test]
fn gather_success_required() -> GDResult<()> {
let result = maybe_gather!(GatherToggle::Enforce, gather_success(15));
assert_eq!(result, Some(15));
Ok(())
}
#[test]
fn gather_fail_dont_gather() -> GDResult<()> {
let result = maybe_gather!(GatherToggle::Skip, gather_fail("dont"));
assert!(result.is_none());
Ok(())
}
#[test]
fn gather_fail_attempt_gather() -> GDResult<()> {
let result = maybe_gather!(GatherToggle::Try, gather_fail("attempt"));
assert!(result.is_none());
Ok(())
}
#[test]
fn gather_fail_required() {
let inner = || {
let result = maybe_gather!(GatherToggle::Enforce, gather_fail("required"));
assert_eq!(result, Some(10));
Ok::<(), GDError>(())
};
assert!(inner().is_err());
}
}