move core result into core utils

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-10-24 01:31:30 +00:00 committed by strawberry
parent 5cb0a5f676
commit c769fcc347
12 changed files with 2 additions and 3 deletions

View file

@ -10,6 +10,7 @@ pub mod json;
pub mod math;
pub mod mutex_map;
pub mod rand;
pub mod result;
pub mod set;
pub mod stream;
pub mod string;

15
src/core/utils/result.rs Normal file
View file

@ -0,0 +1,15 @@
mod debug_inspect;
mod flat_ok;
mod into_is_ok;
mod log_debug_err;
mod log_err;
mod map_expect;
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,
};
pub type Result<T = (), E = crate::Error> = std::result::Result<T, E>;

View file

@ -0,0 +1,52 @@
use super::Result;
/// Inspect Result values with release-mode elision.
pub trait DebugInspect<T, E> {
/// Inspects an Err contained value in debug-mode. In release-mode closure F
/// is elided.
#[must_use]
fn debug_inspect_err<F: FnOnce(&E)>(self, f: F) -> Self;
/// Inspects an Ok contained value in debug-mode. In release-mode closure F
/// is elided.
#[must_use]
fn debug_inspect<F: FnOnce(&T)>(self, f: F) -> Self;
}
#[cfg(debug_assertions)]
impl<T, E> DebugInspect<T, E> for Result<T, E> {
#[inline]
fn debug_inspect<F>(self, f: F) -> Self
where
F: FnOnce(&T),
{
self.inspect(f)
}
#[inline]
fn debug_inspect_err<F>(self, f: F) -> Self
where
F: FnOnce(&E),
{
self.inspect_err(f)
}
}
#[cfg(not(debug_assertions))]
impl<T, E> DebugInspect<T, E> for Result<T, E> {
#[inline]
fn debug_inspect<F>(self, _: F) -> Self
where
F: FnOnce(&T),
{
self
}
#[inline]
fn debug_inspect_err<F>(self, _: F) -> Self
where
F: FnOnce(&E),
{
self
}
}

View file

@ -0,0 +1,34 @@
use super::Result;
pub trait FlatOk<T> {
/// Equivalent to .transpose().ok().flatten()
fn flat_ok(self) -> Option<T>;
/// Equivalent to .transpose().ok().flatten().ok_or(...)
fn flat_ok_or<E>(self, err: E) -> Result<T, E>;
/// Equivalent to .transpose().ok().flatten().ok_or_else(...)
fn flat_ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E>;
}
impl<T, E> FlatOk<T> for Option<Result<T, E>> {
#[inline]
fn flat_ok(self) -> Option<T> { self.transpose().ok().flatten() }
#[inline]
fn flat_ok_or<Ep>(self, err: Ep) -> Result<T, Ep> { self.flat_ok().ok_or(err) }
#[inline]
fn flat_ok_or_else<Ep, F: FnOnce() -> Ep>(self, err: F) -> Result<T, Ep> { self.flat_ok().ok_or_else(err) }
}
impl<T, E> FlatOk<T> for Result<Option<T>, E> {
#[inline]
fn flat_ok(self) -> Option<T> { self.ok().flatten() }
#[inline]
fn flat_ok_or<Ep>(self, err: Ep) -> Result<T, Ep> { self.flat_ok().ok_or(err) }
#[inline]
fn flat_ok_or_else<Ep, F: FnOnce() -> Ep>(self, err: F) -> Result<T, Ep> { self.flat_ok().ok_or_else(err) }
}

View file

@ -0,0 +1,60 @@
use std::fmt;
use tracing::Level;
use super::Result;
use crate::error;
pub trait ErrLog<T, E>
where
E: fmt::Display,
{
fn log_err(self, level: Level) -> Self;
fn err_log(self) -> Self
where
Self: Sized,
{
self.log_err(Level::ERROR)
}
}
pub trait ErrDebugLog<T, E>
where
E: fmt::Debug,
{
fn log_err_debug(self, level: Level) -> Self;
fn err_debug_log(self) -> Self
where
Self: Sized,
{
self.log_err_debug(Level::ERROR)
}
}
impl<T, E> ErrLog<T, E> for Result<T, E>
where
E: fmt::Display,
{
#[inline]
fn log_err(self, level: Level) -> Self
where
Self: Sized,
{
self.inspect_err(|error| error::inspect_log_level(&error, level))
}
}
impl<T, E> ErrDebugLog<T, E> for Result<T, E>
where
E: fmt::Debug,
{
#[inline]
fn log_err_debug(self, level: Level) -> Self
where
Self: Sized,
{
self.inspect_err(|error| error::inspect_debug_log_level(&error, level))
}
}

View file

@ -0,0 +1,10 @@
use super::Result;
pub trait IntoIsOk<T, E> {
fn into_is_ok(self) -> bool;
}
impl<T, E> IntoIsOk<T, E> for Result<T, E> {
#[inline]
fn into_is_ok(self) -> bool { self.is_ok() }
}

View file

@ -0,0 +1,26 @@
use std::fmt::Debug;
use tracing::Level;
use super::{DebugInspect, Result};
use crate::error;
pub trait LogDebugErr<T, E: Debug> {
#[must_use]
fn err_debug_log(self, level: Level) -> Self;
#[must_use]
fn log_debug_err(self) -> Self
where
Self: Sized,
{
self.err_debug_log(Level::ERROR)
}
}
impl<T, E: Debug> LogDebugErr<T, E> for Result<T, E> {
#[inline]
fn err_debug_log(self, level: Level) -> Self {
self.debug_inspect_err(|error| error::inspect_debug_log_level(&error, level))
}
}

View file

@ -0,0 +1,24 @@
use std::fmt::Display;
use tracing::Level;
use super::Result;
use crate::error;
pub trait LogErr<T, E: Display> {
#[must_use]
fn err_log(self, level: Level) -> Self;
#[must_use]
fn log_err(self) -> Self
where
Self: Sized,
{
self.err_log(Level::ERROR)
}
}
impl<T, E: Display> LogErr<T, E> for Result<T, E> {
#[inline]
fn err_log(self, level: Level) -> Self { self.inspect_err(|error| error::inspect_log_level(&error, level)) }
}

View file

@ -0,0 +1,15 @@
use std::fmt::Debug;
use super::Result;
pub trait MapExpect<T> {
/// Calls expect(msg) on the mapped Result value. This is similar to
/// map(Result::unwrap) but composes an expect call and message without
/// requiring a closure.
fn map_expect(self, msg: &str) -> Option<T>;
}
impl<T, E: Debug> MapExpect<T> for Option<Result<T, E>> {
#[inline]
fn map_expect(self, msg: &str) -> Option<T> { self.map(|result| result.expect(msg)) }
}

View file

@ -0,0 +1,12 @@
use super::Result;
use crate::Error;
pub trait NotFound<T> {
#[must_use]
fn is_not_found(&self) -> bool;
}
impl<T> NotFound<T> for Result<T, Error> {
#[inline]
fn is_not_found(&self) -> bool { self.as_ref().is_err_and(Error::is_not_found) }
}

View file

@ -0,0 +1,17 @@
use std::convert::Infallible;
use super::{DebugInspect, Result};
use crate::error;
pub trait UnwrapInfallible<T> {
fn unwrap_infallible(self) -> T;
}
impl<T> UnwrapInfallible<T> for Result<T, Infallible> {
#[inline]
fn unwrap_infallible(self) -> T {
// SAFETY: Branchless unwrap for errors that can never happen. In debug
// mode this is asserted.
unsafe { self.debug_inspect_err(error::infallible).unwrap_unchecked() }
}
}