Compare commits
11 Commits
Author | SHA1 | Date |
---|---|---|
|
b8723cc8d0 | 2 days ago |
|
e2358483c9 | 5 days ago |
|
003986677f | 5 days ago |
|
c830b1728b | 6 days ago |
|
d31d09366f | 1 week ago |
|
8d7f9399d2 | 1 week ago |
|
3b1299c176 | 1 week ago |
|
765270feaf | 1 week ago |
|
4539f87528 | 1 week ago |
|
e6c0714575 | 1 week ago |
|
bcdbec60ca | 2 weeks ago |
@ -0,0 +1,127 @@
|
|||||||
|
//! Extensions
|
||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Run an expression on an named value with a result type `Result<T, U>`.
|
||||||
|
/// Where `T` and `U` have *the same API surface* for the duration of the provided expression.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// If there is a value `let mut value: Result<T, U>`, where `T: Write` & `U: BufWrite`;
|
||||||
|
/// the expression `value.flush()` is valid for both `T` and `U`.
|
||||||
|
/// Therefore, it can be simplified to be called as so: `unwrap_either(mut value => value.flush())`.
|
||||||
|
///
|
||||||
|
/// # Reference capture vs. `move` capture.
|
||||||
|
/// Note that by default, the identified value is **moved** *into* the expression.
|
||||||
|
/// The type of reference can be controlled by appending `ref`, `mut`, or `ref mut` to the ident.
|
||||||
|
///
|
||||||
|
/// Identifier capture table:
|
||||||
|
/// - **none** ~default~ - Capture by move, value is immutable in expression.
|
||||||
|
/// - `mut` - Capture by move, value is mutable in expression.
|
||||||
|
/// - `ref` - Capture by ref, value is immutable (`&value`) in expression.
|
||||||
|
/// - `ref mut` - Capture by mutable ref, value is mutable (`&mut value`) in expression. (__NOTE__: `value` must be defined as mutable to take a mutable reference of it.)
|
||||||
|
///
|
||||||
|
/// Essentially the same rules as any `match` branch pattern.
|
||||||
|
macro_rules! unwrap_either {
|
||||||
|
($res:ident => $($rest:tt)+) => {
|
||||||
|
match $res {
|
||||||
|
Ok(ref mut $res) => $($rest)+,
|
||||||
|
Err(ref mut $res) => $($rest)+,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(ref mut $res:ident => $($rest:tt)+) => {
|
||||||
|
match $res {
|
||||||
|
Ok(ref mut $res) => $($rest)+,
|
||||||
|
Err(ref mut $res) => $($rest)+,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(ref $res:ident => $($rest:tt)+) => {
|
||||||
|
match $res {
|
||||||
|
Ok(ref $res) => $($rest)+,
|
||||||
|
Err(ref $res) => $($rest)+,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(mut $res:ident => $($rest:tt)+) => {
|
||||||
|
match $res {
|
||||||
|
Ok(mut $res) => $($rest)+,
|
||||||
|
Err(mut $res) => $($rest)+,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use unwrap_either;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct DisjointString<'a, T: ?Sized>([&'a T]);
|
||||||
|
|
||||||
|
macro_rules! disjoint {
|
||||||
|
[$($ex:expr),+] => {
|
||||||
|
$crate::ext::DisjointString::from_array(& [$($ex),+])
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> DisjointString<'a, T>
|
||||||
|
where T: fmt::Display
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_array<'o: 'a, const N: usize>(strings: &'o [&'a T; N]) -> &'o Self
|
||||||
|
{
|
||||||
|
Self::new(strings.as_slice())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub const fn new<'o: 'a>(strings: &'o [&'a T]) -> &'o Self
|
||||||
|
{
|
||||||
|
// SAFETY: Transparent newtype wrapper over `[&'a T]`
|
||||||
|
unsafe {
|
||||||
|
std::mem::transmute(strings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
impl<'a, T: ?Sized> DisjointString<'a, T>
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
pub const fn len(&self) -> usize
|
||||||
|
{
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &T> + ExactSizeIterator + std::iter::FusedIterator + std::iter::DoubleEndedIterator
|
||||||
|
{
|
||||||
|
self.0.iter().map(|&x| x)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn into_iter<'o: 'a>(&'o self) -> impl Iterator<Item = &'a T> + ExactSizeIterator + std::iter::FusedIterator + std::iter::DoubleEndedIterator + 'o
|
||||||
|
{
|
||||||
|
self.0.into_iter().map(|&x|x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> AsRef<[&'a T]> for DisjointString<'a, T>
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn as_ref(&self) -> &[&'a T]
|
||||||
|
{
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> fmt::Display for DisjointString<'a, T>
|
||||||
|
where T: fmt::Display
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
for &s in &self.0 {
|
||||||
|
s.fmt(f)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) use disjoint;
|
Loading…
Reference in new issue