#[cfg(all(feature = "serde", feature = "tracing"))]
use crate::as_valuable::AsValuable;
#[cfg(feature = "unstable")]
use crate::output::Output;
#[cfg(all(feature = "async", feature = "unstable", feature = "serde"))]
use crate::socket::{Request, Socket};
use crate::{
fmt::{Debugged, OptionDisplay, ResultDisplay, StatusDisplay},
is::Is,
seq_visitor::SeqVisitor,
};
#[cfg(feature = "async")]
use crate::{into_stream::IntoStream, process::ProcessBuilder, read_value::ReadValue, run_for::RunForError};
#[cfg(feature = "tui")]
use crate::{
rope::{atoms::Atom, builder::RopeBuilder, rope::Rope},
transpose::Transpose,
};
use anyhow::{Context, Error as AnyhowError};
#[cfg(feature = "async")]
use bytes::Buf;
#[cfg(all(feature = "async", feature = "http"))]
use bytes::Bytes;
use camino::{Utf8Path, Utf8PathBuf};
#[cfg(feature = "async")]
use futures::{
Sink, SinkExt, Stream, StreamExt, TryFuture,
future::{Either, JoinAll},
stream::{Filter, FuturesUnordered},
};
use num::{
Bounded, NumCast, One, ToPrimitive, Zero,
traits::{SaturatingAdd, SaturatingSub},
};
#[cfg(feature = "tui")]
use palette::IntoColor;
#[cfg(all(feature = "async", feature = "http"))]
use poem::Body as PoemBody;
#[cfg(feature = "http")]
use poem::{Endpoint, IntoResponse, web::websocket::Message as PoemMessage};
#[cfg(all(feature = "http", feature = "serde"))]
use poem_openapi::error::ParseRequestPayloadError;
#[cfg(feature = "http")]
use poem_openapi::payload::{Binary as PoemBinary, Json as PoemJson};
#[cfg(feature = "tui")]
use ratatui::{
Frame,
layout::Rect,
style::{Style, Styled},
text::{Line, Span},
widgets::{Block, StatefulWidget, Widget},
};
#[cfg(feature = "http")]
use reqwest::{RequestBuilder, Response};
#[cfg(feature = "serde")]
use rmp_serde::{decode::Error as RmpDecodeError, encode::Error as RmpEncodeError};
#[cfg(any(feature = "http", feature = "serde"))]
use serde::Serialize;
#[cfg(feature = "serde")]
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer};
#[cfg(feature = "serde")]
use serde_json::{Error as SerdeJsonError, Value as Json, value::Index as SerdeJsonIndex};
#[cfg(feature = "serde")]
use serde_yaml_ng::Error as SerdeYamlError;
use std::{
borrow::{Borrow, BorrowMut, Cow},
collections::HashMap,
error::Error as StdError,
fmt::{Debug, Display},
fs::File,
future::Ready,
hash::Hash,
io::{BufReader, BufWriter, Error as IoError, Read, Write},
iter::{Once, Peekable, Repeat},
mem::ManuallyDrop,
ops::{ControlFlow, Index, IndexMut, Range},
path::{Path, PathBuf},
pin::Pin,
str::{FromStr, Utf8Error},
string::FromUtf8Error,
sync::Arc,
task::Poll,
time::Instant,
};
#[cfg(feature = "async")]
use std::{fs::Metadata, process::ExitStatus};
#[cfg(any(feature = "async", feature = "tui"))]
use tokio::{
fs::File as TokioFile,
io::{AsyncRead, BufReader as TokioBufReader},
};
#[cfg(feature = "async")]
use tokio::{
io::{AsyncReadExt, AsyncWrite, AsyncWriteExt, BufWriter as TokioBufWriter},
sync::oneshot::Sender as OneshotSender,
task::{JoinHandle, JoinSet, LocalSet},
time::Duration,
time::{Interval, Sleep, Timeout},
};
#[cfg(feature = "async")]
use tokio_util::{
codec::{Framed, LengthDelimitedCodec, LinesCodec},
io::StreamReader,
};
#[cfg(feature = "tracing")]
use tracing::Level;
use tuplities_remove::TupleRemove;
use typenum::{U0, U1, U2};
#[cfg(feature = "tui")]
use unicode_segmentation::{GraphemeIndices, Graphemes, UnicodeSegmentation};
#[cfg(all(feature = "serde", feature = "tracing"))]
use valuable::Value;
pub type BoxError = Box<dyn StdError + Send + Sync>;
#[allow(async_fn_in_trait)]
pub trait Utils {
const CRLF: &str = "\r\n";
const IS_EXTENDED: bool = true;
const LF: &str = "\n";
const READ_FROM_CLIPBOARD_COMMAND: &str = "pbpaste";
const WRITE_TO_CLIPBOARD_COMMAND: &str = "pbcopy";
const URI_PREFIX: &str = "file://";
#[cfg(feature = "async")]
async fn abort_all_and_wait<T: 'static>(&mut self)
where
Self: BorrowMut<JoinSet<T>>,
{
let join_set = self.borrow_mut();
join_set.abort_all();
while join_set.join_next().await.is_some() {}
}
fn absolute_utf8(&self) -> Result<Cow<'_, Utf8Path>, IoError>
where
Self: AsRef<Utf8Path>,
{
let path = self.as_ref();
if path.is_absolute() {
path.to_cow_borrowed().ok()
} else {
camino::absolute_utf8(path)?.into_cow_owned::<Utf8Path>().ok()
}
}
async fn achain<T: Future>(self, rhs: T) -> T::Output
where
Self: Future + Sized,
{
self.await;
rhs.await
}
#[cfg(feature = "tui")]
fn add_span<'a, T: Into<Span<'a>>>(self, span: T) -> Line<'a>
where
Self: Into<Line<'a>>,
{
let mut line = self.into();
line.spans.push(span.into());
line
}
fn anyhow_msg_error(self) -> AnyhowError
where
Self: 'static + Debug + Display + Send + Sized + Sync,
{
AnyhowError::msg(self)
}
fn anyhow_error(self) -> AnyhowError
where
Self: Into<AnyhowError>,
{
self.into()
}
fn anyhow_result<T, E: Into<AnyhowError>>(self) -> Result<T, AnyhowError>
where
Self: Is<Result<T, E>>,
{
self.into_self().map_err(E::into)
}
fn arc(self) -> Arc<Self>
where
Self: Sized,
{
Arc::new(self)
}
fn assign(&mut self, other: Self)
where
Self: Sized,
{
*self = other;
}
fn assign_to(self, other: &mut Self)
where
Self: Sized,
{
other.assign(self);
}
async fn async_with<T>(self, next: impl Future<Output = T>) -> T
where
Self: Future + Sized,
{
self.await;
next.await
}
fn as_borrowed<'a, B: ?Sized + ToOwned>(&'a self) -> &'a B
where
Self: Borrow<Cow<'a, B>>,
{
self.borrow().borrow()
}
fn as_immut(&mut self) -> &Self {
self
}
fn as_ptr(&self) -> *const Self {
std::ptr::from_ref(self)
}
fn as_ptr_mut(&mut self) -> *mut Self {
std::ptr::from_mut(self)
}
fn as_utf8(&self) -> Result<&str, Utf8Error>
where
Self: AsRef<[u8]>,
{
std::str::from_utf8(self.as_ref())
}
fn as_utf8_path(&self) -> &Utf8Path
where
Self: AsRef<Utf8Path>,
{
self.as_ref()
}
#[cfg(all(feature = "serde", feature = "tracing"))]
fn as_valuable(&self) -> Value<'_>
where
Self: AsValuable,
{
AsValuable::as_valuable(self)
}
#[cfg(feature = "tui")]
fn bordered_block<'a>(self) -> Block<'a>
where
Self: Into<Line<'a>> + Sized,
{
Block::bordered().title(self)
}
fn buf_reader(self) -> BufReader<Self>
where
Self: Read + Sized,
{
BufReader::new(self)
}
#[cfg(any(feature = "async", feature = "tui"))]
fn buf_reader_async(self) -> TokioBufReader<Self>
where
Self: AsyncRead + Sized,
{
TokioBufReader::new(self)
}
fn buf_writer(self) -> BufWriter<Self>
where
Self: Write + Sized,
{
BufWriter::new(self)
}
#[cfg(feature = "async")]
fn buf_writer_async(self) -> TokioBufWriter<Self>
where
Self: AsyncWrite + Sized,
{
TokioBufWriter::new(self)
}
fn cast_or_max<T: Bounded + NumCast>(self) -> T
where
Self: Sized + ToPrimitive,
{
match T::from(self) {
Some(value) => value,
None => T::max_value(),
}
}
fn cast_ref<T>(&self) -> &T {
let ptr = std::ptr::from_ref(self).cast::<T>();
let value = unsafe { ptr.as_ref() };
value.unwrap()
}
fn cat<T: Display>(&self, rhs: T) -> String
where
Self: Display,
{
std::format!("{self}{rhs}")
}
fn check_next<T>(self) -> Result<T, AnyhowError>
where
Self: Is<Option<T>>,
{
match self.into_self() {
Some(item) => item.ok(),
None => anyhow::bail!(
"sequence of {type_name} items is exhausted",
type_name = Self::type_name(),
),
}
}
fn check_present<T>(self) -> Result<T, AnyhowError>
where
Self: Is<Option<T>>,
{
match self.into_self() {
Some(item) => item.ok(),
None => anyhow::bail!(
"keyed entry of type {type_name} is not present in the collection",
type_name = Self::type_name(),
),
}
}
#[cfg(feature = "http")]
async fn check_status(self) -> Result<Response, AnyhowError>
where
Self: Is<Response>,
{
let response = self.into_self();
let status = response.status();
if !status.is_client_error() && !status.is_server_error() {
return response.ok();
}
let text = match response.text().await {
Ok(text) => text,
Err(error) => std::format!("unable to read response text: {error}"),
};
anyhow::bail!("({status}) {text}")
}
#[must_use]
fn clamped(self, min: Self, max: Self) -> Self
where
Self: PartialOrd + Sized,
{
num::clamp(self, min, max)
}
#[cfg(feature = "tui")]
fn collect_atoms<'a>(&mut self) -> String
where
Self: Iterator<Item = Atom<'a>>,
{
self.map(|atom| atom.extended_grapheme).collect()
}
fn convert<T: From<Self>>(self) -> T
where
Self: Sized,
{
self.into()
}
fn contains_eq<Q, K>(&self, query: Q) -> bool
where
Self: AsRef<[K]>,
for<'a> &'a K: PartialEq<Q>,
{
self.find_eq(query).is_some()
}
fn context_path<T, E, C: 'static + Display + Send + Sync, P: AsRef<Path>>(
self,
context: C,
path: P,
) -> Result<T, AnyhowError>
where
Self: Context<T, E> + Sized,
{
let context = std::format!("{context}: {path}", path = path.as_ref().display());
self.context(context)
}
#[must_use]
fn copied(&self) -> Self
where
Self: Copy + Sized,
{
*self
}
fn copy_to(&self, dst: impl AsRef<Path>) -> Result<u64, IoError>
where
Self: AsRef<Path>,
{
std::fs::copy(self, dst)
}
#[cfg(feature = "async")]
async fn write_to_clipboard(&self) -> Result<ExitStatus, AnyhowError>
where
Self: AsRef<[u8]>,
{
let mut process = ProcessBuilder::new(Self::WRITE_TO_CLIPBOARD_COMMAND).build()?;
process
.stdin_mut()
.write_all_then_async(self.as_ref())
.await?
.flush()
.await?;
process.run().await?.ok()
}
#[cfg(feature = "async")]
#[must_use]
async fn read_from_clipboard() -> Result<String, AnyhowError> {
let mut process = ProcessBuilder::new(Self::READ_FROM_CLIPBOARD_COMMAND).build()?;
let string = process.stdout_mut().read_to_string_async().await?;
process.run().await?;
string.ok()
}
fn create(&self) -> Result<File, IoError>
where
Self: AsRef<Path>,
{
File::create(self)
}
fn create_dir_all(&self) -> Result<(), IoError>
where
Self: AsRef<Path>,
{
std::fs::create_dir_all(self)
}
fn cycle_in_place(&mut self, amount: isize, total: usize)
where
Self: BorrowMut<usize>,
{
let current = self.borrow_mut();
*current = amount
.saturating_add_unsigned(*current)
.rem_euclid(total.cast_or_max())
.cast_or_max();
}
fn debug(&self) -> Debugged<'_, Self>
where
Self: Debug + Sized,
{
Debugged::new(self)
}
fn decrement(&mut self)
where
Self: One + SaturatingSub,
{
self.saturating_sub_assign(&Self::one());
}
#[must_use]
fn decremented(&self) -> Self
where
Self: One + SaturatingSub,
{
self.saturating_sub(&Self::one())
}
fn deserialize_from_seq<'de, D: Deserializer<'de>, X: Deserialize<'de>, Y, E: Display, F: Fn(X) -> Result<Y, E>>(
deserializer: D,
func: F,
) -> Result<Self, D::Error>
where
Self: Default + Extend<Y>,
{
let seq_visitor = SeqVisitor::new(func);
deserializer.deserialize_seq(seq_visitor)
}
#[cfg(feature = "unstable")]
fn end_err<T>(self) -> Output<T, Self>
where
Self: Sized,
{
Output::EndErr(self)
}
#[cfg(feature = "unstable")]
fn end_ok<T, E>(&self) -> Output<T, E> {
Output::EndOk
}
fn err<T>(self) -> Result<T, Self>
where
Self: Sized,
{
Err(self)
}
fn expand_user(&self) -> Cow<'_, Utf8Path>
where
Self: AsRef<str>,
{
let path_str = self.as_ref();
if let Some(relative_path_str) = path_str.strip_prefix("~/")
&& let Some(home_dirpath) = Self::home_dirpath()
{
home_dirpath.join(relative_path_str).into_cow_owned()
} else {
path_str.as_utf8_path().to_cow_borrowed()
}
}
fn unexpand_user(&self) -> Cow<'_, Utf8Path>
where
Self: AsRef<str>,
{
let path_str = self.as_ref();
if let Some(home_dirpath) = Self::home_dirpath()
&& let Some(relative_path_str) = path_str.strip_prefix(home_dirpath.as_str())
{
if relative_path_str.is_empty() {
"~".convert::<Utf8PathBuf>().into_cow_owned()
} else if relative_path_str.as_utf8_path().is_absolute() {
"~".cat(relative_path_str).convert::<Utf8PathBuf>().into_cow_owned()
} else {
path_str.as_utf8_path().to_cow_borrowed()
}
} else {
path_str.as_utf8_path().to_cow_borrowed()
}
}
#[cfg(feature = "tui")]
fn extended_graphemes(&self) -> Graphemes<'_>
where
Self: AsRef<str>,
{
self.as_ref().graphemes(Self::IS_EXTENDED)
}
#[cfg(feature = "tui")]
fn extended_grapheme_byte_indices(&self) -> impl Iterator<Item = usize>
where
Self: AsRef<str>,
{
self.extended_grapheme_and_byte_index_pairs().map(Utils::into_first)
}
#[cfg(feature = "tui")]
fn extended_grapheme_and_byte_index_pairs(&self) -> GraphemeIndices<'_>
where
Self: AsRef<str>,
{
self.as_ref().grapheme_indices(Self::IS_EXTENDED)
}
#[cfg(feature = "tui")]
fn extended_grapheme_substring(&self, range: Range<usize>) -> &str
where
Self: AsRef<str>,
{
let string = self.as_ref();
let mut extended_grapheme_byte_indices = string.extended_grapheme_byte_indices().skip(range.start);
let Some(begin_byte_index) = extended_grapheme_byte_indices.next() else { return "" };
let mut extended_grapheme_byte_indices = extended_grapheme_byte_indices.skip(range.len());
let end_byte_index = extended_grapheme_byte_indices.next().unwrap_or(string.len());
&string[begin_byte_index..end_byte_index]
}
#[cfg(feature = "async")]
fn filter_sync(
self,
mut func: impl FnMut(&Self::Item) -> bool,
) -> Filter<Self, Ready<bool>, impl FnMut(&Self::Item) -> Ready<bool>>
where
Self: Sized + StreamExt,
{
self.filter(move |x| func(x).ready())
}
fn file_name_ok(&self) -> Result<&str, AnyhowError>
where
Self: AsRef<Utf8Path>,
{
self.as_ref().file_name().context("path has no file name")
}
fn file_name_or_self(&self) -> &str
where
Self: AsRef<Utf8Path>,
{
let path = self.as_ref();
if let Some(file_name) = path.file_name() {
file_name
} else {
path.as_str()
}
}
fn find_eq<Q, K>(&self, query: Q) -> Option<(usize, &K)>
where
Self: AsRef<[K]>,
for<'a> &'a K: PartialEq<Q>,
{
self.as_ref().iter().enumerate().find(|(_index, key)| *key == query)
}
fn find_substr<'a>(&'a self, substr: &str) -> Option<(&'a str, &'a str, &'a str)>
where
Self: AsRef<str>,
{
let string = self.as_ref();
let begin_index = string.find(substr)?;
let end_index = begin_index.saturating_add(substr.len());
let prefix = &string[..begin_index];
let substr = &string[begin_index..end_index];
let suffix = &string[end_index..];
let triple = (prefix, substr, suffix);
triple.some()
}
fn has_happened(self) -> bool
where
Self: Is<Instant>,
{
self.into_self() <= Instant::now()
}
#[must_use]
fn home_dirpath() -> Option<Utf8PathBuf> {
home::home_dir()?.try_convert::<Utf8PathBuf>().ok()
}
fn if_else<T>(self, true_value: T, false_value: T) -> T
where
Self: Is<bool>,
{
if self.into_self() { true_value } else { false_value }
}
fn increment(&mut self)
where
Self: One + SaturatingAdd,
{
*self = self.as_immut().incremented();
}
#[must_use]
fn incremented(&self) -> Self
where
Self: One + SaturatingAdd,
{
self.saturating_add(&Self::one())
}
fn index_into<T: Index<Self> + ?Sized>(self, collection: &T) -> &T::Output
where
Self: Sized,
{
collection.index(self)
}
fn index_into_mut<T: IndexMut<Self> + ?Sized>(self, collection: &mut T) -> &mut T::Output
where
Self: Sized,
{
collection.index_mut(self)
}
fn insert_mut<'a, K: 'a + Eq + Hash, V>(&'a mut self, key: K, value: V) -> &'a mut V
where
Self: BorrowMut<HashMap<K, V>>,
{
self.borrow_mut().entry(key).insert_entry(value).into_mut()
}
#[must_use]
fn interpolate(
self,
old_min: impl ToPrimitive,
old_max: impl ToPrimitive,
new_min: impl ToPrimitive,
new_max: impl ToPrimitive,
) -> Self
where
Self: Bounded + NumCast + ToPrimitive,
{
let old_min = old_min.cast_or_max::<f64>();
let old_max = old_max.cast_or_max::<f64>();
let new_min = new_min.cast_or_max::<f64>();
let new_max = new_max.cast_or_max::<f64>();
let old_value = self.cast_or_max::<f64>().clamped(old_min, old_max);
let new_value = new_min + (new_max - new_min) * (old_value - old_min) / (old_max - old_min);
let new_value = new_value.clamped(new_min, new_max);
new_value.cast_or_max()
}
fn into_box(self) -> Box<Self>
where
Self: Sized,
{
Box::new(self)
}
fn into_break<C>(self) -> ControlFlow<Self, C>
where
Self: Sized,
{
ControlFlow::Break(self)
}
#[cfg(feature = "tui")]
fn into_color<T>(self) -> T
where
Self: IntoColor<T>,
{
IntoColor::into_color(self)
}
fn into_ok_err<T>(self) -> T
where
Self: Is<Result<T, T>>,
{
match self.into_self() {
Ok(value) | Err(value) => value,
}
}
fn into_continue<B>(self) -> ControlFlow<B, Self>
where
Self: Sized,
{
ControlFlow::Continue(self)
}
fn into_cow_owned<B: ?Sized + ToOwned<Owned = Self>>(self) -> Cow<'static, B>
where
Self: Sized,
{
Cow::Owned(self)
}
#[cfg(feature = "http")]
fn into_endpoint(self) -> impl Endpoint<Output = Self>
where
Self: Clone + IntoResponse + Sync,
{
let func = move |_request| self.clone();
poem::endpoint::make_sync(func)
}
fn into_fn_ptr<X, Y>(func: fn(X) -> Y) -> fn(X) -> Y {
func
}
fn into_first(self) -> Self::Type
where
Self: Sized + TupleRemove<U0>,
{
self.remove().0
}
fn into_second(self) -> Self::Type
where
Self: Sized + TupleRemove<U1>,
{
self.remove().0
}
fn into_third(self) -> Self::Type
where
Self: Sized + TupleRemove<U2>,
{
self.remove().0
}
#[cfg(feature = "async")]
fn into_interval(self) -> Interval
where
Self: Is<Duration>,
{
tokio::time::interval(self.into_self())
}
#[cfg(feature = "async")]
fn into_left<R>(self) -> Either<Self, R>
where
Self: Sized,
{
Either::Left(self)
}
#[cfg(feature = "tui")]
fn into_line<'a>(self) -> Line<'a>
where
Self: Into<Cow<'a, str>>,
{
self.into().into()
}
fn into_manually_drop(self) -> ManuallyDrop<Self>
where
Self: Sized,
{
ManuallyDrop::new(self)
}
#[cfg(feature = "async")]
fn into_stream_reader<B: Buf, E: Into<IoError>>(self) -> StreamReader<Self, B>
where
Self: Sized + Stream<Item = Result<B, E>>,
{
StreamReader::new(self)
}
#[cfg(feature = "async")]
fn into_length_delimited_frames(self) -> Framed<Self, LengthDelimitedCodec>
where
Self: Sized,
{
Framed::new(self, LengthDelimitedCodec::new())
}
#[cfg(feature = "async")]
fn into_line_frames(self) -> Framed<Self, LinesCodec>
where
Self: Sized,
{
Framed::new(self, LinesCodec::new())
}
fn into_utf8(self) -> Result<String, FromUtf8Error>
where
Self: Is<Vec<u8>>,
{
String::from_utf8(self.into_self())
}
#[cfg(feature = "async")]
fn into_right<L>(self) -> Either<L, Self>
where
Self: Sized,
{
Either::Right(self)
}
#[cfg(all(feature = "http", feature = "serde"))]
fn into_parse_request_payload_result<T>(self) -> Result<T, ParseRequestPayloadError>
where
Self: Is<Result<T, SerdeJsonError>>,
{
match self.into_self() {
Ok(value) => value.ok(),
Err(serde_json_error) => ParseRequestPayloadError {
reason: serde_json_error.to_string(),
}
.err(),
}
}
#[cfg(feature = "async")]
async fn into_select<T: Future>(self, rhs: T) -> Either<Self::Output, T::Output>
where
Self: Future + Sized,
{
tokio::select! {
value = self => value.into_left(),
value = rhs => value.into_right(),
}
}
#[cfg(feature = "async")]
fn into_stream(self) -> Self::Stream
where
Self: IntoStream + Sized,
{
IntoStream::into_stream(self)
}
fn into_string(self) -> Result<String, AnyhowError>
where
Self: Is<PathBuf>,
{
match self.into_self().into_os_string().into_string() {
Ok(string) => string.ok(),
Err(os_string) => os_string.invalid_utf8_err(),
}
}
#[cfg(feature = "serde")]
fn into_value_from_json<T: DeserializeOwned>(self) -> Result<T, SerdeJsonError>
where
Self: Is<Json>,
{
serde_json::from_value(self.into_self())
}
fn invalid_utf8_err<T>(&self) -> Result<T, AnyhowError>
where
Self: Debug,
{
anyhow::bail!("{self:?} is not valid utf-8")
}
fn io_error(self) -> IoError
where
Self: Into<BoxError>,
{
IoError::other(self)
}
fn io_result<T, E: Into<BoxError>>(self) -> Result<T, IoError>
where
Self: Is<Result<T, E>>,
{
self.into_self().map_err(E::io_error)
}
fn is_non_empty<T: Iterator>(&mut self) -> bool
where
Self: BorrowMut<Peekable<T>>,
{
!self.is_empty()
}
fn is_empty<T: Iterator>(&mut self) -> bool
where
Self: BorrowMut<Peekable<T>>,
{
self.borrow_mut().peek().is_none()
}
#[allow(clippy::wrong_self_convention)]
fn is_less_than<T: PartialOrd>(self, rhs: T) -> bool
where
Self: Into<T>,
{
self.into() < rhs
}
fn is_positive(&self) -> bool
where
Self: PartialOrd + Zero,
{
&Self::zero() < self
}
fn is_newline(&self) -> bool
where
Self: AsRef<str>,
{
let string = self.as_ref();
(string == Self::CRLF) || (string == Self::LF)
}
fn iter_next(&mut self) -> Option<Self::Item>
where
Self: Iterator,
{
self.next()
}
#[cfg(feature = "async")]
fn join_all(self) -> JoinAll<<Self as IntoIterator>::Item>
where
Self: IntoIterator<Item: Future> + Sized,
{
futures::future::join_all(self)
}
#[cfg(feature = "async")]
async fn join_all_into<T>(self) -> T
where
Self: IntoIterator<Item: Future> + Sized,
T: FromIterator<<Self::Item as Future>::Output>,
{
self.join_all().await.into_iter().collect()
}
fn join_path(self, component: impl AsRef<Utf8Path>) -> Utf8PathBuf
where
Self: Into<Utf8PathBuf>,
{
let mut path = self.into();
path.push(component);
path
}
fn len_range<T: SaturatingSub>(&self) -> T
where
Self: Borrow<Range<T>>,
{
let range = self.borrow();
range.end.saturating_sub(&range.start)
}
#[cfg(feature = "tracing")]
fn level<T, E>(&self) -> Level
where
Self: Borrow<Result<T, E>>,
{
if self.borrow().is_ok() {
Level::INFO
} else {
Level::WARN
}
}
#[cfg(feature = "tracing")]
#[must_use]
fn log(self) -> Self
where
Self: Display + Sized,
{
tracing::info!(value = %self);
self
}
#[cfg(feature = "tracing")]
#[must_use]
fn log_debug(self) -> Self
where
Self: Debug + Sized,
{
tracing::info!(value = ?self);
self
}
#[cfg(any(feature = "tracing", feature = "tui"))]
fn log_error(&self)
where
Self: Display,
{
tracing::warn!(error = %self, "error: {self:#}");
}
#[cfg(any(feature = "tracing", feature = "tui"))]
#[must_use]
fn log_if_error<T, E: Display>(self) -> Self
where
Self: Borrow<Result<T, E>> + Sized,
{
if let Err(error) = self.borrow() {
error.log_error();
}
self
}
fn map_collect<Y, T: FromIterator<Y>>(self, func: impl FnMut(Self::Item) -> Y) -> T
where
Self: IntoIterator + Sized,
{
self.into_iter().map(func).collect::<T>()
}
fn map_into<Y, X: Into<Y>>(self) -> Option<Y>
where
Self: Is<Option<X>>,
{
self.into_self().map(X::into)
}
fn map_as_ref<'a, Y: ?Sized, X: 'a + AsRef<Y>>(&'a self) -> Option<&'a Y>
where
Self: Borrow<Option<X>>,
{
self.borrow().as_ref().map(X::as_ref)
}
fn map_range<X, Y>(self, mut func: impl FnMut(X) -> Y) -> Range<Y>
where
Self: Is<Range<X>>,
{
let range = self.into_self();
let start = func(range.start);
let end = func(range.end);
start..end
}
fn max_assign(&mut self, mut other: Self)
where
Self: Ord + Sized,
{
if self < &mut other {
*self = other;
}
}
fn max_assign_to(self, other: &mut Self)
where
Self: Ord + Sized,
{
other.max_assign(self);
}
fn mem_drop(self)
where
Self: Sized,
{
std::mem::drop(self);
}
#[must_use]
fn mem_replace(&mut self, value: Self) -> Self
where
Self: Sized,
{
std::mem::replace(self, value)
}
#[must_use]
fn mem_take(&mut self) -> Self
where
Self: Default,
{
std::mem::take(self)
}
#[cfg(feature = "async")]
async fn metadata_async(&self) -> Result<Metadata, IoError>
where
Self: AsRef<Path>,
{
tokio::fs::metadata(self).await
}
fn min_assign(&mut self, mut other: Self)
where
Self: Ord + Sized,
{
if &mut other < self {
*self = other;
}
}
fn mut_push<T>(&mut self, item: T) -> &mut T
where
Self: BorrowMut<Vec<T>>,
{
let vec = self.borrow_mut();
vec.push(item);
vec.last_mut().unwrap()
}
fn none<T>(&self) -> Option<T> {
None
}
fn ok<E>(self) -> Result<Self, E>
where
Self: Sized,
{
Ok(self)
}
fn once(self) -> Once<Self>
where
Self: Sized,
{
std::iter::once(self)
}
fn open(&self) -> Result<File, IoError>
where
Self: AsRef<Path>,
{
File::open(self)
}
#[cfg(any(feature = "async", feature = "tui"))]
async fn open_async(&self) -> Result<TokioFile, IoError>
where
Self: AsRef<Path>,
{
TokioFile::open(self).await
}
fn option_display<T: Display>(&self) -> OptionDisplay<'_, T>
where
Self: Borrow<Option<T>>,
{
self.borrow().pipe_into(OptionDisplay::new)
}
#[cfg(feature = "unstable")]
fn output_ok<E>(self) -> Output<Self, E>
where
Self: Sized,
{
Output::Ok(self)
}
fn pair<T>(self, rhs: T) -> (Self, T)
where
Self: Sized,
{
(self, rhs)
}
fn parse_unchecked<T: FromStr>(&self) -> T
where
Self: AsRef<str>,
<T as FromStr>::Err: Debug,
{
self.as_ref().parse().unwrap()
}
fn pin(self) -> Pin<Box<Self>>
where
Self: Sized,
{
Box::pin(self)
}
fn pipe<X, Y, Z, F: FnMut(Y) -> Z>(mut self, mut func: F) -> impl FnMut(X) -> Z
where
Self: Sized + FnMut(X) -> Y,
{
move |x| self(x).pipe_into(&mut func)
}
fn poll_ready(self) -> Poll<Self>
where
Self: Sized,
{
Poll::Ready(self)
}
fn pipe_into<T, F: FnOnce(Self) -> T>(self, func: F) -> T
where
Self: Sized,
{
func(self)
}
#[cfg(feature = "http")]
fn poem_binary(self) -> PoemBinary<Self>
where
Self: Sized,
{
PoemBinary(self)
}
#[cfg(feature = "http")]
fn poem_binary_message(self) -> PoemMessage
where
Self: Is<Vec<u8>>,
{
PoemMessage::Binary(self.into_self())
}
#[cfg(feature = "http")]
fn poem_json(self) -> PoemJson<Self>
where
Self: Sized,
{
PoemJson(self)
}
#[cfg(all(feature = "async", feature = "http"))]
fn poem_stream_body<O: 'static + Into<Bytes>, E: 'static + Into<IoError>>(self) -> PoemBinary<PoemBody>
where
Self: 'static + Send + Sized + Stream<Item = Result<O, E>>,
{
PoemBody::from_bytes_stream(self).poem_binary()
}
#[cfg(feature = "http")]
fn poem_text_message(self) -> PoemMessage
where
Self: Is<String>,
{
PoemMessage::Text(self.into_self())
}
fn predicate_lt(&self) -> impl Fn(&Self) -> bool
where
Self: PartialOrd,
{
|other| other < self
}
fn println(&self)
where
Self: Display,
{
std::println!("{self}");
}
fn print(&self)
where
Self: Display,
{
std::print!("{self}");
}
fn push_to<T: Extend<Self>>(self, collection: &mut T)
where
Self: Sized,
{
collection.extend(self.once());
}
fn push_all_to<T: Extend<Self::Item>>(self, collection: &mut T)
where
Self: IntoIterator + Sized,
{
collection.extend(self);
}
#[cfg(feature = "http")]
fn query_all<T: Serialize>(self, name: &str, values: impl IntoIterator<Item = T>) -> RequestBuilder
where
Self: Is<RequestBuilder>,
{
let mut request_builder = self.into_self();
for value in values {
request_builder = request_builder.query_one(name, value);
}
request_builder
}
#[cfg(feature = "http")]
fn query_one<T: Serialize>(self, name: &str, value: impl Into<Option<T>>) -> RequestBuilder
where
Self: Is<RequestBuilder>,
{
let query: &[(&str, T)] = if let Some(value) = value.into() {
&[(name, value)]
} else {
&[]
};
let request_builder = self.into_self();
request_builder.query(query)
}
fn range_from_len(self, len: Self) -> Range<Self>
where
Self: SaturatingAdd,
{
let end = self.saturating_add(&len);
self..end
}
#[cfg(feature = "tui")]
fn ratatui_rect(self) -> Rect
where
Self: Into<(u16, u16)>,
{
let (width, height) = self.into();
Rect::new(0, 0, width, height)
}
#[cfg(feature = "async")]
async fn read_to_string_async(&mut self) -> Result<String, IoError>
where
Self: AsyncReadExt + Unpin,
{
let mut string = String::new();
self.read_to_string(&mut string).await?;
string.ok()
}
#[cfg(feature = "async")]
async fn read_to_string_fs_async(self) -> ReadValue<Self>
where
Self: AsRef<Path> + Sized,
{
let result = tokio::fs::read_to_string(self.as_ref()).await;
ReadValue::new(self, result)
}
fn ready(self) -> Ready<Self>
where
Self: Sized,
{
std::future::ready(self)
}
fn ref_immut(&self) -> &Self {
self
}
fn ref_mut(&mut self) -> &mut Self {
self
}
#[cfg(feature = "tui")]
fn render_to(self, frame: &mut Frame, area: Rect)
where
Self: Widget + Sized,
{
frame.render_widget(self, area);
}
#[cfg(feature = "tui")]
fn render_with_state(self, frame: &mut Frame, area: Rect, state: &mut Self::State)
where
Self: StatefulWidget + Sized,
{
frame.render_stateful_widget(self, area, state);
}
fn repeat(self) -> Repeat<Self>
where
Self: Clone,
{
std::iter::repeat(self)
}
fn result_display<T, E>(&self) -> ResultDisplay<'_, T, E>
where
Self: Borrow<Result<T, E>>,
{
self.borrow().pipe_into(ResultDisplay::new)
}
fn reversed<X, Y>(self) -> (Y, X)
where
Self: Is<(X, Y)>,
{
let (x, y) = self.into_self();
y.pair(x)
}
#[cfg(feature = "tui")]
fn to_rope(&mut self) -> Result<Rope, IoError>
where
Self: Read,
{
let mut rope_builder = RopeBuilder::default();
while let Some(buffer) = rope_builder.buffer_mut() {
let num_bytes_read = self.read(buffer)?;
rope_builder.on_read(num_bytes_read)?;
}
rope_builder.build().ok()
}
#[cfg(all(feature = "async", feature = "tui"))]
async fn to_rope_async(&mut self) -> Result<Rope, IoError>
where
Self: AsyncRead + Unpin,
{
let mut rope_builder = RopeBuilder::default();
while let Some(buffer) = rope_builder.buffer_mut() {
let num_bytes_read = self.read(buffer).await?;
rope_builder.on_read(num_bytes_read)?;
}
rope_builder.build().ok()
}
#[cfg(feature = "async")]
async fn run_for(mut self, duration: Duration) -> Result<Self, RunForError<Self::Output>>
where
Self: Future + Sized + Unpin,
{
tokio::select! {
output = &mut self => RunForError::new(output).err(),
() = tokio::time::sleep(duration) => self.ok(),
}
}
#[cfg(feature = "async")]
async fn run_local(self) -> Self::Output
where
Self: Future + Sized,
{
LocalSet::new().run_until(self).await
}
fn remove_file(&self) -> Result<(), IoError>
where
Self: AsRef<Path>,
{
std::fs::remove_file(self)
}
fn remove_prefix(&self, prefix: &str) -> &str
where
Self: AsRef<str>,
{
let string = self.as_ref();
string.strip_prefix(prefix).unwrap_or(string)
}
#[cfg(all(feature = "async", feature = "unstable", feature = "serde"))]
async fn respond_to<T: Request<Response = Self>>(
&self,
mut socket: impl BorrowMut<Socket>,
) -> Result<(), AnyhowError> {
socket.borrow_mut().respond_with::<T>(self).await
}
fn saturating_add_assign(&mut self, rhs: &Self)
where
Self: SaturatingAdd,
{
*self = self.saturating_add(rhs);
}
fn saturating_add_assign_to_both(&self, other_1: &mut Self, other_2: &mut Self)
where
Self: SaturatingAdd,
{
other_1.saturating_add_assign(self);
other_2.saturating_add_assign(self);
}
#[must_use]
fn saturating_add_or_sub(&mut self, rhs: &Self, add: bool) -> Self
where
Self: SaturatingAdd + SaturatingSub,
{
if add {
self.saturating_add(rhs)
} else {
self.saturating_sub(rhs)
}
}
fn saturating_sub_assign(&mut self, rhs: &Self)
where
Self: SaturatingSub,
{
*self = self.saturating_sub(rhs);
}
#[cfg(feature = "async")]
async fn select_all(self) -> <<Self as IntoIterator>::Item as Future>::Output
where
Self: IntoIterator + Sized,
<Self as IntoIterator>::Item: Future,
{
self.into_iter()
.collect::<FuturesUnordered<_>>()
.next()
.wait_then_unwrap_or_pending()
.await
}
#[cfg(feature = "async")]
async fn send_to<T: Sink<Self> + Unpin>(self, mut sink: T) -> Result<(), T::Error>
where
Self: Sized,
{
sink.send(self).await
}
#[cfg(feature = "async")]
fn send_to_oneshot(self, sender: OneshotSender<Self>) -> Result<(), AnyhowError>
where
Self: Sized,
{
sender
.send(self)
.ok()
.context("unable to send value over oneshot channel")
}
fn set_true(&mut self)
where
Self: BorrowMut<bool>,
{
self.borrow_mut().mem_replace(true).mem_drop();
}
fn set_false(&mut self)
where
Self: BorrowMut<bool>,
{
self.borrow_mut().mem_replace(false).mem_drop();
}
fn singleton<T: FromIterator<Self>>(self) -> T
where
Self: Sized,
{
self.once().collect()
}
#[cfg(feature = "async")]
fn sleep(self) -> Sleep
where
Self: Is<Duration>,
{
tokio::time::sleep(self.into_self())
}
fn some(self) -> Option<Self>
where
Self: Sized,
{
Some(self)
}
#[cfg(feature = "async")]
fn spawn_task(self) -> JoinHandle<Self::Output>
where
Self: 'static + Future + Sized + Send,
Self::Output: 'static + Send,
{
tokio::spawn(self)
}
#[cfg(feature = "tui")]
fn split_along_extended_graphemes(&self, max_prefix_size: usize) -> (&str, &str)
where
Self: AsRef<str>,
{
let string = self.as_ref();
let prefix_len = string
.extended_grapheme_byte_indices()
.take_while(|byte_index| *byte_index < max_prefix_size)
.last()
.unwrap_or(0);
string.split_at(prefix_len)
}
fn split_at(&self, index: usize) -> (&str, &str)
where
Self: AsRef<str>,
{
let string = self.as_ref();
let prefix = &string[..index];
let suffix = &string[index..];
(prefix, suffix)
}
fn status_display<T, E: Display>(&self) -> StatusDisplay<'_, T, E>
where
Self: Borrow<Result<T, E>>,
{
self.borrow().pipe_into(StatusDisplay::new)
}
#[cfg(feature = "tui")]
fn stylize<T: Styled>(self, content: T) -> T::Item
where
Self: Into<Style>,
{
content.set_style(self.into())
}
#[cfg(feature = "tui")]
fn subline<'a>(&'a self, range: Range<usize>) -> Line<'a>
where
Self: Borrow<Line<'a>>,
{
let line = self.borrow();
let mut subline = Line::default().set_style(line.style);
let mut extended_grapheme_index = 0;
if line.alignment.is_some() {
subline.alignment = line.alignment.copied();
}
'outer: for span in &line.spans {
for extended_grapheme in span.content.extended_graphemes() {
if range.end <= extended_grapheme_index {
break 'outer;
} else if range.start <= extended_grapheme_index {
Span::styled(extended_grapheme.to_cow_borrowed(), span.style).push_to(&mut subline.spans);
}
extended_grapheme_index.increment();
}
}
subline
}
fn substr_interval(&self, query: &[u8]) -> Option<(usize, usize)>
where
Self: AsRef<[u8]>,
{
let bytes = self.as_ref();
let predicate = |substr| substr == query;
let query_len = query.len();
let begin = bytes.windows(query_len).position(predicate)?;
let end = begin + query_len;
(begin, end).some()
}
#[cfg(feature = "serde")]
fn take_json<T: DeserializeOwned>(&mut self, index: impl SerdeJsonIndex) -> Result<T, SerdeJsonError>
where
Self: BorrowMut<Json>,
{
self.borrow_mut()
.get_mut(index)
.unwrap_or(&mut Json::Null)
.mem_take()
.into_value_from_json()
}
#[cfg(feature = "async")]
fn timeout(self, duration: Duration) -> Timeout<Self>
where
Self: Future + Sized,
{
tokio::time::timeout(duration, self)
}
fn to_cow_borrowed(&self) -> Cow<'_, Self>
where
Self: ToOwned,
{
Cow::Borrowed(self)
}
fn toggle(&mut self)
where
Self: BorrowMut<bool>,
{
let bool_value = self.borrow_mut();
*bool_value = !*bool_value;
}
#[cfg(feature = "serde")]
fn to_json(&self) -> Result<Json, SerdeJsonError>
where
Self: Serialize,
{
serde_json::to_value(self)
}
#[cfg(feature = "serde")]
fn to_json_bytes(&self) -> Result<Vec<u8>, SerdeJsonError>
where
Self: Serialize,
{
serde_json::to_vec(self)
}
#[cfg(feature = "serde")]
fn to_json_object(&self, key: &str) -> Json
where
Self: Serialize,
{
serde_json::json!({key: self})
}
#[cfg(feature = "serde")]
fn to_json_str(&self) -> Result<String, SerdeJsonError>
where
Self: Serialize,
{
serde_json::to_string(self)
}
fn to_owned_opt<T: ToOwned>(&self) -> Option<T::Owned>
where
Self: Borrow<Option<T>>,
{
self.borrow().as_ref().map(T::to_owned)
}
#[cfg(feature = "serde")]
fn to_rmp_bytes(&self) -> Result<Vec<u8>, RmpEncodeError>
where
Self: Serialize,
{
rmp_serde::to_vec(self)
}
fn to_uri(&self) -> Result<String, IoError>
where
Self: AsRef<Utf8Path>,
{
Self::URI_PREFIX.cat(self.absolute_utf8()?).ok()
}
#[cfg(feature = "serde")]
fn to_value_from_json_slice<'a, T: Deserialize<'a>>(&'a self) -> Result<T, SerdeJsonError>
where
Self: AsRef<[u8]>,
{
serde_json::from_slice(self.as_ref())
}
#[cfg(feature = "serde")]
fn to_value_from_json_reader<T: DeserializeOwned>(self) -> Result<T, SerdeJsonError>
where
Self: Read + Sized,
{
serde_json::from_reader(self)
}
#[cfg(feature = "serde")]
fn to_value_from_rmp_slice<'a, T: Deserialize<'a>>(&'a self) -> Result<T, RmpDecodeError>
where
Self: AsRef<[u8]>,
{
rmp_serde::from_slice(self.as_ref())
}
#[cfg(feature = "serde")]
fn to_value_from_value<T: DeserializeOwned>(&self) -> Result<T, SerdeJsonError>
where
Self: Serialize,
{
self.to_json()?.into_value_from_json()
}
#[cfg(feature = "serde")]
fn to_value_from_yaml_slice<'a, T: Deserialize<'a>>(&'a self) -> Result<T, SerdeYamlError>
where
Self: AsRef<[u8]>,
{
serde_yaml_ng::from_slice(self.as_ref())
}
#[cfg(feature = "serde")]
fn to_value_from_yaml_reader<T: DeserializeOwned>(self) -> Result<T, SerdeYamlError>
where
Self: Read + Sized,
{
serde_yaml_ng::from_reader(self)
}
#[must_use]
fn translate_to(&mut self, value: Self) -> Self
where
Self: SaturatingSub,
{
let difference = value.saturating_sub(self);
*self = value;
difference
}
fn transfer_from_to(&self, src: &mut Self, dst: &mut Self)
where
Self: SaturatingAdd + SaturatingSub,
{
src.saturating_sub_assign(self);
dst.saturating_add_assign(self);
}
#[cfg(feature = "tui")]
#[must_use]
fn transpose(&self) -> Self
where
Self: Transpose + Sized,
{
Transpose::to_transpose(self)
}
fn try_convert<T: TryFrom<Self>>(self) -> Result<T, T::Error>
where
Self: Sized,
{
self.try_into()
}
#[cfg(feature = "async")]
async fn try_join_all(self) -> Result<Vec<<Self::Item as TryFuture>::Ok>, <Self::Item as TryFuture>::Error>
where
Self: IntoIterator<Item: TryFuture> + Sized,
{
futures::future::try_join_all(self).await
}
#[cfg(feature = "async")]
async fn try_join_all_into<T, E>(self) -> Result<T, E>
where
Self: IntoIterator<Item: TryFuture> + Sized,
T: FromIterator<<Self::Item as TryFuture>::Ok>,
E: From<<Self::Item as TryFuture>::Error>,
{
self.try_join_all().await?.into_iter().collect::<T>().ok()
}
#[cfg(feature = "async")]
async fn try_wait<T, E: 'static + Send + Sync>(self) -> Result<T, AnyhowError>
where
Self: Is<JoinHandle<Result<T, E>>>,
AnyhowError: From<E>,
{
self.into_self().await??.ok()
}
#[must_use]
fn type_name() -> &'static str {
std::any::type_name::<Self>()
}
fn unit(&self) {}
async fn wait_then_unwrap_or_pending<T>(self) -> T
where
Self: Future<Output = Option<T>> + Sized,
{
match self.await {
Some(value) => value,
None => std::future::pending().await,
}
}
async fn unwrap_or_pending_then_wait<F: Future + Unpin>(&mut self) -> F::Output
where
Self: BorrowMut<Option<F>>,
{
if let Some(future) = self.borrow_mut().as_mut() {
future.await
} else {
std::future::pending().await
}
}
fn with<T>(&self, value: T) -> T {
value
}
fn with_item_pushed<T>(self, item: T) -> Vec<T>
where
Self: Is<Vec<T>>,
{
let mut vec = self.into_self();
vec.push(item);
vec
}
fn with_str_pushed(self, rhs: &str) -> String
where
Self: Is<String>,
{
let mut string = self.into_self();
string.push_str(rhs);
string
}
#[cfg(feature = "serde")]
fn write_as_json_to<T: Write>(&self, writer: T) -> Result<(), SerdeJsonError>
where
Self: Serialize,
{
serde_json::to_writer(writer, self)
}
fn write_all_then(&mut self, bytes: &[u8]) -> Result<&mut Self, IoError>
where
Self: Write,
{
self.write_all(bytes)?.with(self).ok()
}
#[cfg(feature = "async")]
async fn write_all_then_async(&mut self, bytes: &[u8]) -> Result<&mut Self, IoError>
where
Self: AsyncWriteExt + Unpin,
{
self.write_all(bytes).await?.with(self).ok()
}
}
impl<T: ?Sized> Utils for T {}