From 6b0eb7608d06fbfce663e4775196cfd3c7bae643 Mon Sep 17 00:00:00 2001
From: Jason Volk <jason@zemos.net>
Date: Thu, 31 Oct 2024 07:33:16 +0000
Subject: [PATCH] add Filter extension to Result

Signed-off-by: Jason Volk <jason@zemos.net>
---
 src/core/utils/result.rs        |  5 +++--
 src/core/utils/result/filter.rs | 21 +++++++++++++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 src/core/utils/result/filter.rs

diff --git a/src/core/utils/result.rs b/src/core/utils/result.rs
index 9a60d19e..fb1b7b95 100644
--- a/src/core/utils/result.rs
+++ b/src/core/utils/result.rs
@@ -1,4 +1,5 @@
 mod debug_inspect;
+mod filter;
 mod flat_ok;
 mod into_is_ok;
 mod log_debug_err;
@@ -8,8 +9,8 @@ mod not_found;
 mod unwrap_infallible;
 
 pub use self::{
-	debug_inspect::DebugInspect, flat_ok::FlatOk, into_is_ok::IntoIsOk, log_debug_err::LogDebugErr, log_err::LogErr,
-	map_expect::MapExpect, not_found::NotFound, unwrap_infallible::UnwrapInfallible,
+	debug_inspect::DebugInspect, filter::Filter, flat_ok::FlatOk, into_is_ok::IntoIsOk, log_debug_err::LogDebugErr,
+	log_err::LogErr, map_expect::MapExpect, not_found::NotFound, unwrap_infallible::UnwrapInfallible,
 };
 
 pub type Result<T = (), E = crate::Error> = std::result::Result<T, E>;
diff --git a/src/core/utils/result/filter.rs b/src/core/utils/result/filter.rs
new file mode 100644
index 00000000..f11d3632
--- /dev/null
+++ b/src/core/utils/result/filter.rs
@@ -0,0 +1,21 @@
+use super::Result;
+
+pub trait Filter<T, E> {
+	/// Similar to Option::filter
+	#[must_use]
+	fn filter<P, U>(self, predicate: P) -> Self
+	where
+		P: FnOnce(&T) -> Result<(), U>,
+		E: From<U>;
+}
+
+impl<T, E> Filter<T, E> for Result<T, E> {
+	#[inline]
+	fn filter<P, U>(self, predicate: P) -> Self
+	where
+		P: FnOnce(&T) -> Result<(), U>,
+		E: From<U>,
+	{
+		self.and_then(move |t| predicate(&t).map(move |()| t).map_err(Into::into))
+	}
+}