Skip to main content

mkutils/
utils.rs

1#[cfg(feature = "serde")]
2use crate::as_valuable::AsValuable;
3#[cfg(feature = "fmt")]
4use crate::fmt::{Debugged, OptionDisplay, ResultDisplay};
5#[cfg(any(feature = "ropey", feature = "tui"))]
6use crate::geometry::PointUsize;
7use crate::is::Is;
8#[cfg(feature = "output")]
9use crate::output::Output;
10#[cfg(feature = "process")]
11use crate::process::ProcessBuilder;
12#[cfg(feature = "ropey")]
13use crate::rope_builder::RopeBuilder;
14#[cfg(any(feature = "serde", feature = "tui"))]
15use crate::seq_visitor::SeqVisitor;
16#[cfg(feature = "socket")]
17use crate::socket::{Request, Socket};
18#[cfg(feature = "tracing")]
19use crate::status::Status;
20#[cfg(any(feature = "ropey", feature = "tui"))]
21use crate::transpose::Transpose;
22#[cfg(feature = "async")]
23use crate::{into_stream::IntoStream, read_value::ReadValue, run_for::RunForError};
24#[cfg(any(
25    feature = "async",
26    feature = "fs",
27    feature = "process",
28    feature = "reqwest",
29    feature = "socket",
30    feature = "tui",
31))]
32use anyhow::{Context, Error as AnyhowError};
33#[cfg(feature = "async")]
34use bytes::Buf;
35#[cfg(feature = "poem")]
36use bytes::Bytes;
37#[cfg(feature = "fs")]
38use camino::{Utf8Path, Utf8PathBuf};
39#[cfg(any(feature = "async", feature = "poem"))]
40use futures::Stream;
41#[cfg(feature = "async")]
42use futures::{
43    Sink, SinkExt, StreamExt, TryFuture,
44    future::{Either, JoinAll},
45    stream::{Filter, FuturesUnordered},
46};
47#[cfg(any(feature = "ropey", feature = "misc", feature = "tui"))]
48use num::{Bounded, NumCast, ToPrimitive, Zero};
49#[cfg(feature = "tui")]
50use num::{
51    One,
52    traits::{SaturatingAdd, SaturatingSub},
53};
54#[cfg(feature = "tui")]
55use palette::IntoColor;
56#[cfg(feature = "poem")]
57use poem::{Body as PoemBody, Endpoint, IntoResponse, web::websocket::Message as PoemMessage};
58#[cfg(feature = "poem")]
59use poem_openapi::{error::ParseRequestPayloadError, payload::Binary as PoemBinary, payload::Json as PoemJson};
60#[cfg(feature = "tui")]
61use ratatui::{
62    Frame,
63    layout::Rect,
64    style::Styled,
65    text::{Line, Span},
66    widgets::{Block, StatefulWidget, Widget},
67};
68#[cfg(feature = "reqwest")]
69use reqwest::{RequestBuilder, Response};
70#[cfg(feature = "rmp")]
71use rmp_serde::{decode::Error as RmpDecodeError, encode::Error as RmpEncodeError};
72#[cfg(feature = "ropey")]
73use ropey::{Rope, RopeSlice, iter::Chunks, iter::Lines};
74#[cfg(any(feature = "rmp", feature = "serde", feature = "tui"))]
75use serde::Deserialize;
76#[cfg(any(feature = "serde", feature = "tui"))]
77use serde::Deserializer;
78#[cfg(any(feature = "reqwest", feature = "rmp", feature = "serde"))]
79use serde::Serialize;
80#[cfg(feature = "serde")]
81use serde::de::DeserializeOwned;
82#[cfg(any(feature = "poem", feature = "serde"))]
83use serde_json::Error as SerdeJsonError;
84#[cfg(feature = "serde")]
85use serde_json::{Value as Json, value::Index as SerdeJsonIndex};
86#[cfg(feature = "serde")]
87use serde_yaml_ng::Error as SerdeYamlError;
88#[cfg(any(
89    feature = "async",
90    feature = "fs",
91    feature = "process",
92    feature = "reqwest",
93    feature = "socket",
94    feature = "tui",
95))]
96use std::fmt::Debug;
97#[cfg(feature = "fs")]
98use std::path::PathBuf;
99#[cfg(feature = "process")]
100use std::process::ExitStatus;
101use std::{
102    borrow::{Borrow, BorrowMut, Cow},
103    collections::HashMap,
104    error::Error as StdError,
105    fmt::Display,
106    fs::File,
107    future::Ready,
108    hash::Hash,
109    io::{BufReader, BufWriter, Error as IoError, Read, Write},
110    iter::{Once, Peekable, Repeat},
111    mem::ManuallyDrop,
112    ops::{Add, ControlFlow, Index, IndexMut, Range},
113    path::Path,
114    pin::Pin,
115    str::Utf8Error,
116    string::FromUtf8Error,
117    sync::Arc,
118    task::Poll,
119    time::Instant,
120};
121#[cfg(feature = "async")]
122use std::{fs::Metadata, time::Duration};
123#[cfg(any(feature = "async", feature = "process"))]
124use tokio::io::{AsyncReadExt, AsyncWriteExt};
125#[cfg(any(feature = "async", feature = "ropey"))]
126use tokio::{
127    fs::File as TokioFile,
128    io::{AsyncRead, BufReader as TokioBufReader},
129};
130#[cfg(feature = "async")]
131use tokio::{
132    io::{AsyncWrite, BufWriter as TokioBufWriter},
133    sync::oneshot::Sender as OneshotSender,
134    task::JoinHandle,
135    task::{JoinSet, LocalSet},
136    time::{Interval, Sleep, Timeout},
137};
138#[cfg(feature = "async")]
139use tokio_util::{
140    codec::{Framed, LengthDelimitedCodec, LinesCodec},
141    io::StreamReader,
142};
143#[cfg(feature = "tracing")]
144use tracing::Level;
145#[cfg(any(feature = "ropey", feature = "tui"))]
146use unicode_segmentation::{GraphemeIndices, Graphemes, UnicodeSegmentation};
147#[cfg(feature = "serde")]
148use valuable::Value;
149
150pub type BoxError = Box<dyn StdError + Send + Sync>;
151
152#[allow(async_fn_in_trait)]
153pub trait Utils {
154    const CRLF: &str = "\r\n";
155    const DEFAULT_ROPE_BUILDER_BUFFER_SIZE: usize = 8192;
156    const IS_EXTENDED: bool = true;
157    const LF: &str = "\n";
158    const READ_FROM_CLIPBOARD_COMMAND: &str = "pbpaste";
159    const WRITE_TO_CLIPBOARD_COMMAND: &str = "pbcopy";
160    const URI_PREFIX: &str = "file://";
161
162    #[cfg(feature = "async")]
163    async fn abort_all_and_wait<T: 'static>(&mut self)
164    where
165        Self: BorrowMut<JoinSet<T>>,
166    {
167        let join_set = self.borrow_mut();
168
169        join_set.abort_all();
170
171        while join_set.join_next().await.is_some() {}
172    }
173
174    #[cfg(feature = "fs")]
175    fn absolute_utf8(&self) -> Result<Cow<'_, Utf8Path>, IoError>
176    where
177        Self: AsRef<Utf8Path>,
178    {
179        let path = self.as_ref();
180
181        if path.is_absolute() {
182            path.to_cow_borrowed().ok()
183        } else {
184            camino::absolute_utf8(path)?.into_cow_owned::<Utf8Path>().ok()
185        }
186    }
187
188    async fn achain<T: Future>(self, rhs: T) -> T::Output
189    where
190        Self: Future + Sized,
191    {
192        self.await;
193
194        rhs.await
195    }
196
197    #[cfg(feature = "tui")]
198    fn add_span<'a, T: Into<Span<'a>>>(self, span: T) -> Line<'a>
199    where
200        Self: Into<Line<'a>>,
201    {
202        let mut line = self.into();
203
204        line.spans.push(span.into());
205
206        line
207    }
208
209    #[cfg(any(
210        feature = "async",
211        feature = "fs",
212        feature = "process",
213        feature = "reqwest",
214        feature = "socket",
215        feature = "tui",
216    ))]
217    fn anyhow_msg_error(self) -> AnyhowError
218    where
219        Self: 'static + Debug + Display + Send + Sized + Sync,
220    {
221        AnyhowError::msg(self)
222    }
223
224    #[cfg(any(
225        feature = "async",
226        feature = "fs",
227        feature = "process",
228        feature = "reqwest",
229        feature = "socket",
230        feature = "tui",
231    ))]
232    fn anyhow_error(self) -> AnyhowError
233    where
234        Self: Into<AnyhowError>,
235    {
236        self.into()
237    }
238
239    #[cfg(any(
240        feature = "async",
241        feature = "fs",
242        feature = "process",
243        feature = "reqwest",
244        feature = "socket",
245        feature = "tui",
246    ))]
247    fn anyhow_result<T, E: Into<AnyhowError>>(self) -> Result<T, AnyhowError>
248    where
249        Self: Is<Result<T, E>>,
250    {
251        self.into_self().map_err(E::into)
252    }
253
254    fn arc(self) -> Arc<Self>
255    where
256        Self: Sized,
257    {
258        Arc::new(self)
259    }
260
261    async fn async_with<T>(self, next: impl Future<Output = T>) -> T
262    where
263        Self: Future + Sized,
264    {
265        self.await;
266
267        next.await
268    }
269
270    fn as_borrowed<'a, B: ?Sized + ToOwned>(&'a self) -> &'a B
271    where
272        Self: Borrow<Cow<'a, B>>,
273    {
274        self.borrow().borrow()
275    }
276
277    fn as_immut(&mut self) -> &Self {
278        &*self
279    }
280
281    fn as_ptr(&self) -> *const Self {
282        std::ptr::from_ref(self)
283    }
284
285    fn as_ptr_mut(&mut self) -> *mut Self {
286        std::ptr::from_mut(self)
287    }
288
289    fn as_utf8(&self) -> Result<&str, Utf8Error>
290    where
291        Self: AsRef<[u8]>,
292    {
293        std::str::from_utf8(self.as_ref())
294    }
295
296    #[cfg(feature = "fs")]
297    fn as_utf8_path(&self) -> &Utf8Path
298    where
299        Self: AsRef<Utf8Path>,
300    {
301        self.as_ref()
302    }
303
304    #[cfg(feature = "ropey")]
305    fn as_rope_slice(&self) -> RopeSlice<'_>
306    where
307        Self: Borrow<Rope>,
308    {
309        self.borrow().slice(..)
310    }
311
312    #[cfg(feature = "serde")]
313    fn as_valuable(&self) -> Value<'_>
314    where
315        Self: AsValuable,
316    {
317        AsValuable::as_valuable(self)
318    }
319
320    #[cfg(feature = "tui")]
321    fn bordered_block<'a>(self) -> Block<'a>
322    where
323        Self: Into<Line<'a>> + Sized,
324    {
325        Block::bordered().title(self)
326    }
327
328    fn buf_reader(self) -> BufReader<Self>
329    where
330        Self: Read + Sized,
331    {
332        BufReader::new(self)
333    }
334
335    #[cfg(any(feature = "async", feature = "ropey"))]
336    fn buf_reader_async(self) -> TokioBufReader<Self>
337    where
338        Self: AsyncRead + Sized,
339    {
340        TokioBufReader::new(self)
341    }
342
343    fn buf_writer(self) -> BufWriter<Self>
344    where
345        Self: Write + Sized,
346    {
347        BufWriter::new(self)
348    }
349
350    #[cfg(feature = "async")]
351    fn buf_writer_async(self) -> TokioBufWriter<Self>
352    where
353        Self: AsyncWrite + Sized,
354    {
355        TokioBufWriter::new(self)
356    }
357
358    #[cfg(any(feature = "ropey", feature = "misc", feature = "tui"))]
359    fn cast_or_max<T: Bounded + NumCast>(self) -> T
360    where
361        Self: Sized + ToPrimitive,
362    {
363        match T::from(self) {
364            Some(value) => value,
365            None => T::max_value(),
366        }
367    }
368
369    // NOTE: requires that [Self] and [T] have the same layout (provided by [#[repr(transparent)]]):
370    // [https://stackoverflow.com/questions/79593399/implement-valuablevaluable-on-serde-jsonvalue]
371    fn cast_ref<T>(&self) -> &T {
372        let ptr = std::ptr::from_ref(self).cast::<T>();
373        let value = unsafe { ptr.as_ref() };
374
375        value.unwrap()
376    }
377
378    fn cat<T: Display>(&self, rhs: T) -> String
379    where
380        Self: Display,
381    {
382        std::format!("{self}{rhs}")
383    }
384
385    #[cfg(any(
386        feature = "async",
387        feature = "fs",
388        feature = "process",
389        feature = "reqwest",
390        feature = "socket",
391        feature = "tui",
392    ))]
393    fn check_next<T>(self) -> Result<T, AnyhowError>
394    where
395        Self: Is<Option<T>>,
396    {
397        match self.into_self() {
398            Some(item) => item.ok(),
399            None => anyhow::bail!(
400                "sequence of {type_name} items is exhausted",
401                type_name = Self::type_name(),
402            ),
403        }
404    }
405
406    #[cfg(any(
407        feature = "async",
408        feature = "fs",
409        feature = "process",
410        feature = "reqwest",
411        feature = "socket",
412        feature = "tui",
413    ))]
414    fn check_present<T>(self) -> Result<T, AnyhowError>
415    where
416        Self: Is<Option<T>>,
417    {
418        match self.into_self() {
419            Some(item) => item.ok(),
420            None => anyhow::bail!(
421                "keyed entry of type {type_name} is not present in the collection",
422                type_name = Self::type_name(),
423            ),
424        }
425    }
426
427    // NOTE: [https://docs.rs/reqwest/latest/reqwest/struct.Response.html#method.error_for_status]
428    #[cfg(feature = "reqwest")]
429    async fn check_status(self) -> Result<Response, AnyhowError>
430    where
431        Self: Is<Response>,
432    {
433        let response = self.into_self();
434        let status = response.status();
435
436        if !status.is_client_error() && !status.is_server_error() {
437            return response.ok();
438        }
439
440        let text = match response.text().await {
441            Ok(text) => text,
442            Err(error) => std::format!("unable to read response text: {error}"),
443        };
444
445        anyhow::bail!("({status}) {text}")
446    }
447
448    #[cfg(any(feature = "ropey", feature = "misc", feature = "tui"))]
449    #[must_use]
450    fn clamped(self, min: Self, max: Self) -> Self
451    where
452        Self: PartialOrd + Sized,
453    {
454        num::clamp(self, min, max)
455    }
456
457    fn convert<T: From<Self>>(self) -> T
458    where
459        Self: Sized,
460    {
461        self.into()
462    }
463
464    fn contains_eq<Q, K>(&self, query: Q) -> bool
465    where
466        Self: AsRef<[K]>,
467        for<'a> &'a K: PartialEq<Q>,
468    {
469        self.find_eq(query).is_some()
470    }
471
472    #[cfg(any(
473        feature = "async",
474        feature = "fs",
475        feature = "process",
476        feature = "reqwest",
477        feature = "socket",
478        feature = "tui",
479    ))]
480    fn context_path<T, E, C: 'static + Display + Send + Sync, P: AsRef<Path>>(
481        self,
482        context: C,
483        path: P,
484    ) -> Result<T, AnyhowError>
485    where
486        Self: Context<T, E> + Sized,
487    {
488        let context = std::format!("{context}: {path}", path = path.as_ref().display());
489
490        self.context(context)
491    }
492
493    #[must_use]
494    fn copied(&self) -> Self
495    where
496        Self: Copy + Sized,
497    {
498        *self
499    }
500
501    #[cfg(feature = "process")]
502    async fn write_to_clipboard(&self) -> Result<ExitStatus, AnyhowError>
503    where
504        Self: AsRef<[u8]>,
505    {
506        let mut process = ProcessBuilder::new(Self::WRITE_TO_CLIPBOARD_COMMAND).build()?;
507
508        process
509            .stdin_mut()
510            .write_all_then_async(self.as_ref())
511            .await?
512            .flush()
513            .await?;
514
515        process.run().await?.ok()
516    }
517
518    #[cfg(feature = "process")]
519    #[must_use]
520    async fn read_from_clipboard() -> Result<String, AnyhowError> {
521        let mut process = ProcessBuilder::new(Self::READ_FROM_CLIPBOARD_COMMAND).build()?;
522        let string = process.stdout_mut().read_to_string_async().await?;
523
524        process.run().await?;
525
526        string.ok()
527    }
528
529    fn create(&self) -> Result<File, IoError>
530    where
531        Self: AsRef<Path>,
532    {
533        File::create(self)
534    }
535
536    fn create_dir_all(&self) -> Result<(), IoError>
537    where
538        Self: AsRef<Path>,
539    {
540        std::fs::create_dir_all(self)
541    }
542
543    #[cfg(feature = "misc")]
544    fn cycle_in_place(&mut self, amount: isize, total: usize)
545    where
546        Self: BorrowMut<usize>,
547    {
548        let current = self.borrow_mut();
549
550        // NOTE: [isize::rem_euclid()] returns a nonnegative integer
551        // [https://doc.rust-lang.org/stable/std/primitive.isize.html#method.rem_euclid] so casting as a [usize] is
552        // fine
553        *current = amount
554            .saturating_add_unsigned(*current)
555            .rem_euclid(total.cast_or_max())
556            .cast_or_max();
557    }
558
559    #[cfg(feature = "fmt")]
560    fn debug(self) -> Debugged<Self>
561    where
562        Self: Sized,
563    {
564        Debugged::new(self)
565    }
566
567    #[cfg(feature = "tui")]
568    fn decrement(&mut self)
569    where
570        Self: One + SaturatingSub,
571    {
572        self.saturating_sub_assign(&Self::one());
573    }
574
575    #[cfg(feature = "tui")]
576    #[must_use]
577    fn decremented(&self) -> Self
578    where
579        Self: One + SaturatingSub,
580    {
581        self.saturating_sub(&Self::one())
582    }
583
584    #[cfg(any(feature = "serde", feature = "tui"))]
585    fn deserialize_from_seq<'de, D: Deserializer<'de>, X: Deserialize<'de>, Y, E: Display, F: Fn(X) -> Result<Y, E>>(
586        deserializer: D,
587        func: F,
588    ) -> Result<Self, D::Error>
589    where
590        Self: Default + Extend<Y>,
591    {
592        let seq_visitor = SeqVisitor::new(func);
593
594        deserializer.deserialize_seq(seq_visitor)
595    }
596
597    #[cfg(feature = "output")]
598    fn end_err<T>(self) -> Output<T, Self>
599    where
600        Self: Sized,
601    {
602        Output::EndErr(self)
603    }
604
605    #[cfg(feature = "output")]
606    fn end_ok<T, E>(&self) -> Output<T, E> {
607        Output::EndOk
608    }
609
610    fn err<T>(self) -> Result<T, Self>
611    where
612        Self: Sized,
613    {
614        Err(self)
615    }
616
617    #[cfg(feature = "fs")]
618    fn expand_user(&self) -> Cow<'_, Utf8Path>
619    where
620        Self: AsRef<str>,
621    {
622        let path_str = self.as_ref();
623
624        if let Some(relative_path_str) = path_str.strip_prefix("~/")
625            && let Some(home_dirpath) = Self::home_dirpath()
626        {
627            home_dirpath.join(relative_path_str).into_cow_owned()
628        } else {
629            path_str.as_utf8_path().to_cow_borrowed()
630        }
631    }
632
633    #[cfg(feature = "fs")]
634    fn unexpand_user(&self) -> Cow<'_, Utf8Path>
635    where
636        Self: AsRef<str>,
637    {
638        let path_str = self.as_ref();
639
640        if let Some(home_dirpath) = Self::home_dirpath()
641            && let Some(relative_path_str) = path_str.strip_prefix(home_dirpath.as_str())
642        {
643            if relative_path_str.is_empty() {
644                "~".convert::<Utf8PathBuf>().into_cow_owned()
645            } else if relative_path_str.as_utf8_path().is_absolute() {
646                "~".cat(relative_path_str).convert::<Utf8PathBuf>().into_cow_owned()
647            } else {
648                path_str.as_utf8_path().to_cow_borrowed()
649            }
650        } else {
651            path_str.as_utf8_path().to_cow_borrowed()
652        }
653    }
654
655    #[cfg(any(feature = "ropey", feature = "tui"))]
656    fn extended_graphemes(&self) -> Graphemes<'_>
657    where
658        Self: AsRef<str>,
659    {
660        self.as_ref().graphemes(Self::IS_EXTENDED)
661    }
662
663    #[cfg(any(feature = "ropey", feature = "tui"))]
664    fn extended_grapheme_indices(&self) -> GraphemeIndices<'_>
665    where
666        Self: AsRef<str>,
667    {
668        self.as_ref().grapheme_indices(Self::IS_EXTENDED)
669    }
670
671    #[cfg(feature = "ropey")]
672    fn extended_graphemes_at<'a>(self, extended_graphemes_index_range: Range<usize>) -> impl Iterator<Item = &'a str>
673    where
674        Self: Is<RopeSlice<'a>>,
675    {
676        let extended_graphemes_index_range = extended_graphemes_index_range.borrow();
677
678        self.into_self()
679            .chunks()
680            .flat_map(str::extended_graphemes)
681            .skip(extended_graphemes_index_range.start)
682            .take(extended_graphemes_index_range.len())
683    }
684
685    #[cfg(feature = "ropey")]
686    fn extended_graphemes_at_rect<'a>(
687        self,
688        lines_index_range: Range<usize>,
689        extended_graphemes_index_range: Range<usize>,
690    ) -> impl Iterator<Item = impl Iterator<Item = &'a str>>
691    where
692        Self: Is<RopeSlice<'a>>,
693    {
694        self.into_self()
695            .saturating_lines_at(lines_index_range.start)
696            .take(lines_index_range.len())
697            .map(move |line_rope_slice| line_rope_slice.extended_graphemes_at(extended_graphemes_index_range.clone()))
698    }
699
700    #[cfg(any(feature = "ropey", feature = "tui"))]
701    fn extended_grapheme_substring(&self, range: Range<usize>) -> &str
702    where
703        Self: AsRef<str>,
704    {
705        let string = self.as_ref();
706        let mut extended_grapheme_indices = string.extended_grapheme_indices().skip(range.start);
707        let Some((begin_byte_offset, _begin_extended_grapheme)) = extended_grapheme_indices.next() else {
708            return "";
709        };
710        let mut extended_grapheme_indices = extended_grapheme_indices.skip(range.len());
711        let end_byte_offset = if let Some((end_byte_offset, _end_extended_grapheme)) = extended_grapheme_indices.next()
712        {
713            end_byte_offset
714        } else {
715            string.len()
716        };
717
718        &string[begin_byte_offset..end_byte_offset]
719    }
720
721    #[cfg(feature = "async")]
722    fn filter_sync(
723        self,
724        mut func: impl FnMut(&Self::Item) -> bool,
725    ) -> Filter<Self, Ready<bool>, impl FnMut(&Self::Item) -> Ready<bool>>
726    where
727        Self: Sized + StreamExt,
728    {
729        // TODO: figure out why [func.pipe(bool::ready)] won't work
730        self.filter(move |x| func(x).ready())
731    }
732
733    #[cfg(feature = "fs")]
734    fn file_name_ok(&self) -> Result<&str, AnyhowError>
735    where
736        Self: AsRef<Utf8Path>,
737    {
738        self.as_ref().file_name().context("path has no file name")
739    }
740
741    #[cfg(feature = "fs")]
742    fn file_name_or_self(&self) -> &str
743    where
744        Self: AsRef<Utf8Path>,
745    {
746        let path = self.as_ref();
747
748        if let Some(file_name) = path.file_name() {
749            file_name
750        } else {
751            path.as_str()
752        }
753    }
754
755    fn find_eq<Q, K>(&self, query: Q) -> Option<(usize, &K)>
756    where
757        Self: AsRef<[K]>,
758        for<'a> &'a K: PartialEq<Q>,
759    {
760        self.as_ref().iter().enumerate().find(|(_index, key)| *key == query)
761    }
762
763    fn find_substr<'a>(&'a self, substr: &str) -> Option<(&'a str, &'a str, &'a str)>
764    where
765        Self: AsRef<str>,
766    {
767        let string = self.as_ref();
768        let begin_index = string.find(substr)?;
769        let end_index = begin_index.saturating_add(substr.len());
770        let prefix = &string[..begin_index];
771        let substr = &string[begin_index..end_index];
772        let suffix = &string[end_index..];
773        let triple = (prefix, substr, suffix);
774
775        triple.some()
776    }
777
778    fn has_happened(self) -> bool
779    where
780        Self: Is<Instant>,
781    {
782        self.into_self() <= Instant::now()
783    }
784
785    #[cfg(feature = "fs")]
786    #[must_use]
787    fn home_dirpath() -> Option<Utf8PathBuf> {
788        home::home_dir()?.try_convert::<Utf8PathBuf>().ok()
789    }
790
791    fn if_else<T>(self, true_value: T, false_value: T) -> T
792    where
793        Self: Is<bool>,
794    {
795        if self.into_self() { true_value } else { false_value }
796    }
797
798    fn immutable(&mut self) -> &Self {
799        self
800    }
801
802    #[cfg(feature = "tui")]
803    fn increment(&mut self)
804    where
805        Self: One + SaturatingAdd,
806    {
807        self.saturating_add_assign(&Self::one());
808    }
809
810    #[cfg(feature = "tui")]
811    #[must_use]
812    fn incremented(&self) -> Self
813    where
814        Self: One + SaturatingAdd,
815    {
816        self.saturating_add(&Self::one())
817    }
818
819    fn index_into<T: Index<Self> + ?Sized>(self, collection: &T) -> &T::Output
820    where
821        Self: Sized,
822    {
823        collection.index(self)
824    }
825
826    fn index_into_mut<T: IndexMut<Self> + ?Sized>(self, collection: &mut T) -> &mut T::Output
827    where
828        Self: Sized,
829    {
830        collection.index_mut(self)
831    }
832
833    fn insert_mut<'a, K: 'a + Eq + Hash, V>(&'a mut self, key: K, value: V) -> &'a mut V
834    where
835        Self: BorrowMut<HashMap<K, V>>,
836    {
837        self.borrow_mut().entry(key).insert_entry(value).into_mut()
838    }
839
840    #[cfg(any(feature = "ropey", feature = "misc", feature = "tui"))]
841    #[must_use]
842    fn interpolate(
843        self,
844        old_min: impl ToPrimitive,
845        old_max: impl ToPrimitive,
846        new_min: impl ToPrimitive,
847        new_max: impl ToPrimitive,
848    ) -> Self
849    where
850        Self: Bounded + NumCast + ToPrimitive,
851    {
852        let old_min = old_min.cast_or_max::<f64>();
853        let old_max = old_max.cast_or_max::<f64>();
854        let new_min = new_min.cast_or_max::<f64>();
855        let new_max = new_max.cast_or_max::<f64>();
856        let old_value = self.cast_or_max::<f64>().clamped(old_min, old_max);
857        let new_value = new_min + (new_max - new_min) * (old_value - old_min) / (old_max - old_min);
858        let new_value = new_value.clamped(new_min, new_max);
859
860        new_value.cast_or_max()
861    }
862
863    fn into_box(self) -> Box<Self>
864    where
865        Self: Sized,
866    {
867        Box::new(self)
868    }
869
870    fn into_break<C>(self) -> ControlFlow<Self, C>
871    where
872        Self: Sized,
873    {
874        ControlFlow::Break(self)
875    }
876
877    #[cfg(feature = "tui")]
878    fn into_color<T>(self) -> T
879    where
880        Self: IntoColor<T>,
881    {
882        IntoColor::into_color(self)
883    }
884
885    fn into_common<T>(self) -> T
886    where
887        Self: Is<Result<T, T>>,
888    {
889        match self.into_self() {
890            Ok(value) | Err(value) => value,
891        }
892    }
893
894    fn into_continue<B>(self) -> ControlFlow<B, Self>
895    where
896        Self: Sized,
897    {
898        ControlFlow::Continue(self)
899    }
900
901    fn into_cow_owned<B: ?Sized + ToOwned<Owned = Self>>(self) -> Cow<'static, B>
902    where
903        Self: Sized,
904    {
905        Cow::Owned(self)
906    }
907
908    #[cfg(feature = "poem")]
909    fn into_endpoint(self) -> impl Endpoint<Output = Self>
910    where
911        Self: Clone + IntoResponse + Sync,
912    {
913        let func = move |_request| self.clone();
914
915        poem::endpoint::make_sync(func)
916    }
917
918    #[cfg(feature = "async")]
919    fn into_interval(self) -> Interval
920    where
921        Self: Is<Duration>,
922    {
923        tokio::time::interval(self.into_self())
924    }
925
926    #[cfg(feature = "async")]
927    fn into_left<R>(self) -> Either<Self, R>
928    where
929        Self: Sized,
930    {
931        Either::Left(self)
932    }
933
934    #[cfg(feature = "tui")]
935    fn into_line<'a>(self) -> Line<'a>
936    where
937        Self: Into<Cow<'a, str>>,
938    {
939        self.into().into()
940    }
941
942    fn into_manually_drop(self) -> ManuallyDrop<Self>
943    where
944        Self: Sized,
945    {
946        ManuallyDrop::new(self)
947    }
948
949    #[cfg(feature = "async")]
950    fn into_stream_reader<B: Buf, E: Into<IoError>>(self) -> StreamReader<Self, B>
951    where
952        Self: Sized + Stream<Item = Result<B, E>>,
953    {
954        StreamReader::new(self)
955    }
956
957    #[cfg(feature = "async")]
958    fn into_length_delimited_frames(self) -> Framed<Self, LengthDelimitedCodec>
959    where
960        Self: Sized,
961    {
962        Framed::new(self, LengthDelimitedCodec::new())
963    }
964
965    #[cfg(feature = "async")]
966    fn into_line_frames(self) -> Framed<Self, LinesCodec>
967    where
968        Self: Sized,
969    {
970        Framed::new(self, LinesCodec::new())
971    }
972
973    fn into_utf8(self) -> Result<String, FromUtf8Error>
974    where
975        Self: Is<Vec<u8>>,
976    {
977        String::from_utf8(self.into_self())
978    }
979
980    #[cfg(feature = "async")]
981    fn into_right<L>(self) -> Either<L, Self>
982    where
983        Self: Sized,
984    {
985        Either::Right(self)
986    }
987
988    // NOTE: [https://docs.rs/poem-openapi/latest/src/poem_openapi/payload/json.rs.html]
989    #[cfg(feature = "poem")]
990    fn into_parse_request_payload_result<T>(self) -> Result<T, ParseRequestPayloadError>
991    where
992        Self: Is<Result<T, SerdeJsonError>>,
993    {
994        match self.into_self() {
995            Ok(value) => value.ok(),
996            Err(serde_json_error) => ParseRequestPayloadError {
997                reason: serde_json_error.to_string(),
998            }
999            .err(),
1000        }
1001    }
1002
1003    #[cfg(feature = "async")]
1004    async fn into_select<T: Future>(self, rhs: T) -> Either<Self::Output, T::Output>
1005    where
1006        Self: Future + Sized,
1007    {
1008        tokio::select! {
1009            value = self => value.into_left(),
1010            value = rhs => value.into_right(),
1011        }
1012    }
1013
1014    #[cfg(feature = "tracing")]
1015    fn into_status<T, E>(self) -> Status<T, E>
1016    where
1017        Self: Is<Result<T, E>>,
1018    {
1019        Status::new(self.into_self())
1020    }
1021
1022    #[cfg(feature = "async")]
1023    fn into_stream(self) -> Self::Stream
1024    where
1025        Self: IntoStream + Sized,
1026    {
1027        IntoStream::into_stream(self)
1028    }
1029
1030    #[cfg(feature = "fs")]
1031    fn into_string(self) -> Result<String, AnyhowError>
1032    where
1033        Self: Is<PathBuf>,
1034    {
1035        match self.into_self().into_os_string().into_string() {
1036            Ok(string) => string.ok(),
1037            Err(os_string) => os_string.invalid_utf8_err(),
1038        }
1039    }
1040
1041    #[cfg(feature = "serde")]
1042    fn into_value_from_json<T: DeserializeOwned>(self) -> Result<T, SerdeJsonError>
1043    where
1044        Self: Is<Json>,
1045    {
1046        serde_json::from_value(self.into_self())
1047    }
1048
1049    #[cfg(feature = "fs")]
1050    fn invalid_utf8_err<T>(&self) -> Result<T, AnyhowError>
1051    where
1052        Self: Debug,
1053    {
1054        anyhow::bail!("{self:?} is not valid utf-8")
1055    }
1056
1057    fn io_error(self) -> IoError
1058    where
1059        Self: Into<BoxError>,
1060    {
1061        IoError::other(self)
1062    }
1063
1064    fn io_result<T, E: Into<BoxError>>(self) -> Result<T, IoError>
1065    where
1066        Self: Is<Result<T, E>>,
1067    {
1068        self.into_self().map_err(E::io_error)
1069    }
1070
1071    fn is_non_empty<T: Iterator>(&mut self) -> bool
1072    where
1073        Self: BorrowMut<Peekable<T>>,
1074    {
1075        !self.is_empty()
1076    }
1077
1078    fn is_empty<T: Iterator>(&mut self) -> bool
1079    where
1080        Self: BorrowMut<Peekable<T>>,
1081    {
1082        self.borrow_mut().peek().is_some()
1083    }
1084
1085    #[allow(clippy::wrong_self_convention)]
1086    fn is_less_than<T: PartialOrd>(self, rhs: T) -> bool
1087    where
1088        Self: Into<T>,
1089    {
1090        self.into() < rhs
1091    }
1092
1093    #[cfg(any(feature = "ropey", feature = "misc", feature = "tui"))]
1094    fn is_positive(&self) -> bool
1095    where
1096        Self: PartialOrd + Zero,
1097    {
1098        &Self::zero() < self
1099    }
1100
1101    fn is_newline(&self) -> bool
1102    where
1103        Self: AsRef<str>,
1104    {
1105        let string = self.as_ref();
1106
1107        (string == Self::CRLF) || (string == Self::LF)
1108    }
1109
1110    #[cfg(feature = "async")]
1111    fn join_all(self) -> JoinAll<<Self as IntoIterator>::Item>
1112    where
1113        Self: IntoIterator<Item: Future> + Sized,
1114    {
1115        futures::future::join_all(self)
1116    }
1117
1118    #[cfg(feature = "async")]
1119    async fn join_all_into<T>(self) -> T
1120    where
1121        Self: IntoIterator<Item: Future> + Sized,
1122        T: FromIterator<<Self::Item as Future>::Output>,
1123    {
1124        self.join_all().await.into_iter().collect()
1125    }
1126
1127    #[cfg(any(feature = "ropey", feature = "tui"))]
1128    fn len_extended_graphemes(&self) -> usize
1129    where
1130        Self: AsRef<str>,
1131    {
1132        self.as_ref().extended_graphemes().count()
1133    }
1134
1135    #[cfg(feature = "tracing")]
1136    fn level<T, E>(&self) -> Level
1137    where
1138        Self: Borrow<Result<T, E>>,
1139    {
1140        if self.borrow().is_ok() {
1141            Level::INFO
1142        } else {
1143            Level::WARN
1144        }
1145    }
1146
1147    #[cfg(any(feature = "tui", feature = "tracing"))]
1148    fn log_error(&self)
1149    where
1150        Self: Display,
1151    {
1152        tracing::warn!(error = %self, "error: {self:#}");
1153    }
1154
1155    #[cfg(any(feature = "tui", feature = "tracing"))]
1156    #[must_use]
1157    fn log_if_error<T, E: Display>(self) -> Self
1158    where
1159        Self: Borrow<Result<T, E>> + Sized,
1160    {
1161        if let Err(error) = self.borrow() {
1162            error.log_error();
1163        }
1164
1165        self
1166    }
1167
1168    fn map_collect<Y, T: FromIterator<Y>>(self, func: impl FnMut(Self::Item) -> Y) -> T
1169    where
1170        Self: IntoIterator + Sized,
1171    {
1172        self.into_iter().map(func).collect::<T>()
1173    }
1174
1175    fn map_into<Y, X: Into<Y>>(self) -> Option<Y>
1176    where
1177        Self: Is<Option<X>>,
1178    {
1179        self.into_self().map(X::into)
1180    }
1181
1182    fn map_as_ref<'a, Y: ?Sized, X: 'a + AsRef<Y>>(&'a self) -> Option<&'a Y>
1183    where
1184        Self: Borrow<Option<X>>,
1185    {
1186        self.borrow().as_ref().map(X::as_ref)
1187    }
1188
1189    fn mem_drop(self)
1190    where
1191        Self: Sized,
1192    {
1193        std::mem::drop(self);
1194    }
1195
1196    #[must_use]
1197    fn mem_replace(&mut self, value: Self) -> Self
1198    where
1199        Self: Sized,
1200    {
1201        std::mem::replace(self, value)
1202    }
1203
1204    #[must_use]
1205    fn mem_take(&mut self) -> Self
1206    where
1207        Self: Default,
1208    {
1209        std::mem::take(self)
1210    }
1211
1212    #[cfg(feature = "async")]
1213    async fn metadata_async(&self) -> Result<Metadata, IoError>
1214    where
1215        Self: AsRef<Path>,
1216    {
1217        tokio::fs::metadata(self).await
1218    }
1219
1220    // NOTE: [https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.push_mut]
1221    fn mut_push<T>(&mut self, item: T) -> &mut T
1222    where
1223        Self: BorrowMut<Vec<T>>,
1224    {
1225        let vec = self.borrow_mut();
1226
1227        vec.push(item);
1228
1229        vec.last_mut().unwrap()
1230    }
1231
1232    fn iter_next(&mut self) -> Option<Self::Item>
1233    where
1234        Self: Iterator,
1235    {
1236        self.next()
1237    }
1238
1239    fn none<T>(&self) -> Option<T> {
1240        None
1241    }
1242
1243    #[cfg(feature = "ropey")]
1244    fn num_lines_and_extended_graphemes<'a>(self) -> PointUsize
1245    where
1246        Self: Is<RopeSlice<'a>>,
1247    {
1248        let rope_slice = self.into_self();
1249        let y = rope_slice.len_lines();
1250        let x = rope_slice
1251            .lines()
1252            .map(|line_rope| line_rope.chunks().map(str::len_extended_graphemes).sum())
1253            .max()
1254            .unwrap_or(0);
1255
1256        PointUsize::new(x, y)
1257    }
1258
1259    fn ok<E>(self) -> Result<Self, E>
1260    where
1261        Self: Sized,
1262    {
1263        Ok(self)
1264    }
1265
1266    fn once(self) -> Once<Self>
1267    where
1268        Self: Sized,
1269    {
1270        std::iter::once(self)
1271    }
1272
1273    fn open(&self) -> Result<File, IoError>
1274    where
1275        Self: AsRef<Path>,
1276    {
1277        File::open(self)
1278    }
1279
1280    #[cfg(any(feature = "ropey", feature = "async"))]
1281    async fn open_async(&self) -> Result<TokioFile, IoError>
1282    where
1283        Self: AsRef<Path>,
1284    {
1285        TokioFile::open(self).await
1286    }
1287
1288    #[cfg(feature = "fmt")]
1289    fn option_display(self) -> OptionDisplay<Self>
1290    where
1291        Self: Sized,
1292    {
1293        OptionDisplay::new(self)
1294    }
1295
1296    #[cfg(feature = "output")]
1297    fn output_ok<E>(self) -> Output<Self, E>
1298    where
1299        Self: Sized,
1300    {
1301        Output::Ok(self)
1302    }
1303
1304    fn pair<T>(self, rhs: T) -> (Self, T)
1305    where
1306        Self: Sized,
1307    {
1308        (self, rhs)
1309    }
1310
1311    fn pin(self) -> Pin<Box<Self>>
1312    where
1313        Self: Sized,
1314    {
1315        Box::pin(self)
1316    }
1317
1318    fn pipe<X, Y, Z, F: FnMut(Y) -> Z>(mut self, mut func: F) -> impl FnMut(X) -> Z
1319    where
1320        Self: Sized + FnMut(X) -> Y,
1321    {
1322        move |x| self(x).pipe_into(&mut func)
1323    }
1324
1325    fn poll_ready(self) -> Poll<Self>
1326    where
1327        Self: Sized,
1328    {
1329        Poll::Ready(self)
1330    }
1331
1332    fn pipe_into<T, F: FnOnce(Self) -> T>(self, func: F) -> T
1333    where
1334        Self: Sized,
1335    {
1336        func(self)
1337    }
1338
1339    #[cfg(feature = "poem")]
1340    fn poem_binary(self) -> PoemBinary<Self>
1341    where
1342        Self: Sized,
1343    {
1344        PoemBinary(self)
1345    }
1346
1347    #[cfg(feature = "poem")]
1348    fn poem_binary_message(self) -> PoemMessage
1349    where
1350        Self: Is<Vec<u8>>,
1351    {
1352        PoemMessage::Binary(self.into_self())
1353    }
1354
1355    #[cfg(feature = "poem")]
1356    fn poem_json(self) -> PoemJson<Self>
1357    where
1358        Self: Sized,
1359    {
1360        PoemJson(self)
1361    }
1362
1363    #[cfg(feature = "poem")]
1364    fn poem_stream_body<O: 'static + Into<Bytes>, E: 'static + Into<IoError>>(self) -> PoemBinary<PoemBody>
1365    where
1366        Self: 'static + Send + Sized + Stream<Item = Result<O, E>>,
1367    {
1368        PoemBody::from_bytes_stream(self).poem_binary()
1369    }
1370
1371    #[cfg(feature = "poem")]
1372    fn poem_text_message(self) -> PoemMessage
1373    where
1374        Self: Is<String>,
1375    {
1376        PoemMessage::Text(self.into_self())
1377    }
1378
1379    fn println(&self)
1380    where
1381        Self: Display,
1382    {
1383        std::println!("{self}");
1384    }
1385
1386    fn print(&self)
1387    where
1388        Self: Display,
1389    {
1390        std::print!("{self}");
1391    }
1392
1393    fn push_to<T: Extend<Self>>(self, collection: &mut T)
1394    where
1395        Self: Sized,
1396    {
1397        collection.extend(self.once());
1398    }
1399
1400    fn push_all_to<T: Extend<Self::Item>>(self, collection: &mut T)
1401    where
1402        Self: IntoIterator + Sized,
1403    {
1404        collection.extend(self);
1405    }
1406
1407    #[cfg(feature = "reqwest")]
1408    fn query_all<T: Serialize>(self, name: &str, values: impl IntoIterator<Item = T>) -> RequestBuilder
1409    where
1410        Self: Is<RequestBuilder>,
1411    {
1412        let mut request_builder = self.into_self();
1413
1414        for value in values {
1415            request_builder = request_builder.query_one(name, value);
1416        }
1417
1418        request_builder
1419    }
1420
1421    #[cfg(feature = "reqwest")]
1422    fn query_one<T: Serialize>(self, name: &str, value: impl Into<Option<T>>) -> RequestBuilder
1423    where
1424        Self: Is<RequestBuilder>,
1425    {
1426        let query: &[(&str, T)] = if let Some(value) = value.into() {
1427            &[(name, value)]
1428        } else {
1429            &[]
1430        };
1431        let request_builder = self.into_self();
1432
1433        request_builder.query(query)
1434    }
1435
1436    fn range_from_len(self, len: Self) -> Range<Self>
1437    where
1438        Self: Add<Output = Self> + Copy,
1439    {
1440        let end = self + len;
1441
1442        self..end
1443    }
1444
1445    #[cfg(feature = "tui")]
1446    fn ratatui_rect(self) -> Rect
1447    where
1448        Self: Into<(u16, u16)>,
1449    {
1450        let (width, height) = self.into();
1451        let x = 0;
1452        let y = 0;
1453
1454        Rect { x, y, width, height }
1455    }
1456
1457    #[cfg(any(feature = "async", feature = "process"))]
1458    async fn read_to_string_async(&mut self) -> Result<String, IoError>
1459    where
1460        Self: AsyncReadExt + Unpin,
1461    {
1462        let mut string = String::new();
1463
1464        self.read_to_string(&mut string).await?;
1465
1466        string.ok()
1467    }
1468
1469    #[cfg(feature = "async")]
1470    async fn read_to_string_fs_async(self) -> ReadValue<Self>
1471    where
1472        Self: AsRef<Path> + Sized,
1473    {
1474        let result = tokio::fs::read_to_string(self.as_ref()).await;
1475
1476        ReadValue::new(self, result)
1477    }
1478
1479    fn ready(self) -> Ready<Self>
1480    where
1481        Self: Sized,
1482    {
1483        std::future::ready(self)
1484    }
1485
1486    fn ref_immut(&self) -> &Self {
1487        self
1488    }
1489
1490    fn ref_mut(&mut self) -> &mut Self {
1491        self
1492    }
1493
1494    #[cfg(feature = "tui")]
1495    fn render_to(self, frame: &mut Frame, rect: Rect)
1496    where
1497        Self: Widget + Sized,
1498    {
1499        frame.render_widget(self, rect);
1500    }
1501
1502    #[cfg(feature = "tui")]
1503    fn render_with_state(self, frame: &mut Frame, rect: Rect, state: &mut Self::State)
1504    where
1505        Self: StatefulWidget + Sized,
1506    {
1507        frame.render_stateful_widget(self, rect, state);
1508    }
1509
1510    fn repeat(self) -> Repeat<Self>
1511    where
1512        Self: Clone,
1513    {
1514        std::iter::repeat(self)
1515    }
1516
1517    #[cfg(feature = "fmt")]
1518    fn result_display(self) -> ResultDisplay<Self>
1519    where
1520        Self: Sized,
1521    {
1522        ResultDisplay::new(self)
1523    }
1524
1525    fn reversed<X, Y>(self) -> (Y, X)
1526    where
1527        Self: Is<(X, Y)>,
1528    {
1529        let (x, y) = self.into_self();
1530
1531        y.pair(x)
1532    }
1533
1534    #[cfg(feature = "ropey")]
1535    async fn rope<const N: usize>(&self) -> Result<Rope, IoError>
1536    where
1537        Self: AsRef<Path>,
1538    {
1539        self.open_async()
1540            .await?
1541            .buf_reader_async()
1542            .pipe_into(RopeBuilder::<_, N>::new)
1543            .build()
1544            .await
1545    }
1546
1547    #[cfg(feature = "async")]
1548    async fn run_for(mut self, duration: Duration) -> Result<Self, RunForError<Self::Output>>
1549    where
1550        Self: Future + Sized + Unpin,
1551    {
1552        tokio::select! {
1553            output = &mut self => RunForError::new(output).err(),
1554            () = tokio::time::sleep(duration) => self.ok(),
1555        }
1556    }
1557
1558    #[cfg(feature = "async")]
1559    async fn run_local(self) -> Self::Output
1560    where
1561        Self: Future + Sized,
1562    {
1563        LocalSet::new().run_until(self).await
1564    }
1565
1566    fn remove_file(&self) -> Result<(), IoError>
1567    where
1568        Self: AsRef<Path>,
1569    {
1570        std::fs::remove_file(self)
1571    }
1572
1573    fn remove_prefix(&self, prefix: &str) -> &str
1574    where
1575        Self: AsRef<str>,
1576    {
1577        let string = self.as_ref();
1578
1579        string.strip_prefix(prefix).unwrap_or(string)
1580    }
1581
1582    #[cfg(feature = "socket")]
1583    async fn respond_to<T: Request<Response = Self>>(
1584        &self,
1585        mut socket: impl BorrowMut<Socket>,
1586    ) -> Result<(), AnyhowError> {
1587        socket.borrow_mut().respond::<T>(self).await
1588    }
1589
1590    // TODO-ac2072:
1591    // - add [AsRopeSlice] trait that both [Rope] and [RopeSlice<'_>] implement
1592    // - i was doing this, but it didn't work due to some use of tempoarary variables error
1593    #[cfg(feature = "ropey")]
1594    fn saturating_chunks_at_extended_grapheme<'a>(self, extended_grapheme_index: usize) -> Chunks<'a>
1595    where
1596        Self: Is<RopeSlice<'a>>,
1597    {
1598        self.saturating_chunks_at_char(extended_grapheme_index)
1599    }
1600
1601    // TODO-ac2072
1602    #[cfg(feature = "ropey")]
1603    fn saturating_chunks_at_char<'a>(self, char_index: usize) -> Chunks<'a>
1604    where
1605        Self: Is<RopeSlice<'a>>,
1606    {
1607        let rope_slice = self.into_self();
1608        let char_index = rope_slice.len_chars().min(char_index);
1609
1610        rope_slice.chunks_at_char(char_index).0
1611    }
1612
1613    // TODO-ac2072
1614    #[cfg(feature = "ropey")]
1615    fn saturating_lines_at<'a>(self, line_index: usize) -> Lines<'a>
1616    where
1617        Self: Is<RopeSlice<'a>>,
1618    {
1619        let rope_slice = self.into_self();
1620        let line_index = rope_slice.len_lines().min(line_index);
1621
1622        rope_slice.lines_at(line_index)
1623    }
1624
1625    #[cfg(feature = "tui")]
1626    fn saturating_add_assign(&mut self, rhs: &Self)
1627    where
1628        Self: SaturatingAdd,
1629    {
1630        *self = self.saturating_add(rhs);
1631    }
1632
1633    #[cfg(feature = "tui")]
1634    fn saturating_add_or_sub_in_place_with_max(&mut self, rhs: Self, max_value: Self, add: bool)
1635    where
1636        Self: Ord + SaturatingAdd + SaturatingSub + Sized,
1637    {
1638        let value = if add {
1639            self.saturating_add(&rhs)
1640        } else {
1641            self.saturating_sub(&rhs)
1642        };
1643
1644        *self = value.min(max_value);
1645    }
1646
1647    #[cfg(feature = "tui")]
1648    fn saturating_sub_assign(&mut self, rhs: &Self)
1649    where
1650        Self: SaturatingSub,
1651    {
1652        *self = self.saturating_sub(rhs);
1653    }
1654
1655    #[cfg(feature = "async")]
1656    async fn select_all(self) -> <<Self as IntoIterator>::Item as Future>::Output
1657    where
1658        Self: IntoIterator + Sized,
1659        <Self as IntoIterator>::Item: Future,
1660    {
1661        self.into_iter()
1662            .collect::<FuturesUnordered<_>>()
1663            .next()
1664            .wait_then_unwrap_or_pending()
1665            .await
1666    }
1667
1668    #[cfg(feature = "async")]
1669    async fn send_to<T: Sink<Self> + Unpin>(self, mut sink: T) -> Result<(), T::Error>
1670    where
1671        Self: Sized,
1672    {
1673        sink.send(self).await
1674    }
1675
1676    #[cfg(feature = "async")]
1677    fn send_to_oneshot(self, sender: OneshotSender<Self>) -> Result<(), AnyhowError>
1678    where
1679        Self: Sized,
1680    {
1681        // NOTE: drop error variant which wraps [Self] and may not implement [StdError]
1682        sender
1683            .send(self)
1684            .ok()
1685            .context("unable to send value over oneshot channel")
1686    }
1687
1688    fn set_true(&mut self) -> bool
1689    where
1690        Self: BorrowMut<bool>,
1691    {
1692        self.borrow_mut().mem_replace(true)
1693    }
1694
1695    fn set_false(&mut self) -> bool
1696    where
1697        Self: BorrowMut<bool>,
1698    {
1699        self.borrow_mut().mem_replace(false)
1700    }
1701
1702    fn singleton<T: FromIterator<Self>>(self) -> T
1703    where
1704        Self: Sized,
1705    {
1706        self.once().collect()
1707    }
1708
1709    #[cfg(feature = "tui")]
1710    fn size<T: SaturatingSub>(&self) -> T
1711    where
1712        Self: Borrow<Range<T>>,
1713    {
1714        let range = self.borrow();
1715
1716        range.end.saturating_sub(&range.start)
1717    }
1718
1719    #[cfg(feature = "async")]
1720    fn sleep(self) -> Sleep
1721    where
1722        Self: Is<Duration>,
1723    {
1724        tokio::time::sleep(self.into_self())
1725    }
1726
1727    fn some(self) -> Option<Self>
1728    where
1729        Self: Sized,
1730    {
1731        Some(self)
1732    }
1733
1734    #[cfg(feature = "async")]
1735    fn spawn_task(self) -> JoinHandle<Self::Output>
1736    where
1737        Self: 'static + Future + Sized + Send,
1738        Self::Output: 'static + Send,
1739    {
1740        tokio::spawn(self)
1741    }
1742
1743    #[cfg(any(feature = "ropey", feature = "tui"))]
1744    fn split_along_extended_graphemes(&self, max_prefix_size: usize) -> (&str, &str)
1745    where
1746        Self: AsRef<str>,
1747    {
1748        let string = self.as_ref();
1749        let prefix_len = string
1750            .extended_grapheme_indices()
1751            .map(|(index, _extended_grapheme)| index)
1752            .take_while(|index| *index < max_prefix_size)
1753            .last()
1754            .unwrap_or(0);
1755
1756        string.split_at(prefix_len)
1757    }
1758
1759    fn split_at(&self, index: usize) -> (&str, &str)
1760    where
1761        Self: AsRef<str>,
1762    {
1763        let string = self.as_ref();
1764        let prefix = &string[..index];
1765        let suffix = &string[index..];
1766
1767        (prefix, suffix)
1768    }
1769
1770    #[cfg(feature = "tui")]
1771    fn subline<'a>(&'a self, range: Range<usize>) -> Line<'a>
1772    where
1773        Self: Borrow<Line<'a>>,
1774    {
1775        let line = self.borrow();
1776        let mut subline = Line::default().set_style(line.style);
1777        let mut extended_grapheme_index = 0;
1778
1779        if line.alignment.is_some() {
1780            subline.alignment = line.alignment.copied();
1781        }
1782
1783        'outer: for span in &line.spans {
1784            for extended_grapheme in span.content.extended_graphemes() {
1785                if range.end <= extended_grapheme_index {
1786                    break 'outer;
1787                } else if range.start <= extended_grapheme_index {
1788                    Span::styled(extended_grapheme.to_cow_borrowed(), span.style).push_to(&mut subline.spans);
1789                }
1790
1791                extended_grapheme_index.increment();
1792            }
1793        }
1794
1795        subline
1796    }
1797
1798    // TODO-4eef0b: permit reverse search
1799    fn substr_interval(&self, query: &[u8]) -> Option<(usize, usize)>
1800    where
1801        Self: AsRef<[u8]>,
1802    {
1803        let byte_str = self.as_ref();
1804        let predicate = |substr| substr == query;
1805        let query_len = query.len();
1806        let begin = byte_str.windows(query_len).position(predicate)?;
1807        let end = begin + query_len;
1808
1809        (begin, end).some()
1810    }
1811
1812    #[cfg(feature = "serde")]
1813    fn take_json<T: DeserializeOwned>(&mut self, index: impl SerdeJsonIndex) -> Result<T, SerdeJsonError>
1814    where
1815        Self: BorrowMut<Json>,
1816    {
1817        self.borrow_mut()
1818            .get_mut(index)
1819            .unwrap_or(&mut Json::Null)
1820            .mem_take()
1821            .into_value_from_json()
1822    }
1823
1824    #[cfg(feature = "async")]
1825    fn timeout(self, duration: Duration) -> Timeout<Self>
1826    where
1827        Self: Future + Sized,
1828    {
1829        tokio::time::timeout(duration, self)
1830    }
1831
1832    fn to_cow_borrowed(&self) -> Cow<'_, Self>
1833    where
1834        Self: ToOwned,
1835    {
1836        Cow::Borrowed(self)
1837    }
1838
1839    fn toggle(&mut self)
1840    where
1841        Self: BorrowMut<bool>,
1842    {
1843        let bool_value = self.borrow_mut();
1844
1845        *bool_value = !*bool_value;
1846    }
1847
1848    #[cfg(feature = "serde")]
1849    fn to_json(&self) -> Result<Json, SerdeJsonError>
1850    where
1851        Self: Serialize,
1852    {
1853        serde_json::to_value(self)
1854    }
1855
1856    #[cfg(feature = "serde")]
1857    fn to_json_byte_str(&self) -> Result<Vec<u8>, SerdeJsonError>
1858    where
1859        Self: Serialize,
1860    {
1861        serde_json::to_vec(self)
1862    }
1863
1864    #[cfg(feature = "serde")]
1865    fn to_json_object(&self, key: &str) -> Json
1866    where
1867        Self: Serialize,
1868    {
1869        serde_json::json!({key: self})
1870    }
1871
1872    #[cfg(feature = "serde")]
1873    fn to_json_str(&self) -> Result<String, SerdeJsonError>
1874    where
1875        Self: Serialize,
1876    {
1877        serde_json::to_string(self)
1878    }
1879
1880    #[cfg(feature = "rmp")]
1881    fn to_rmp_byte_str(&self) -> Result<Vec<u8>, RmpEncodeError>
1882    where
1883        Self: Serialize,
1884    {
1885        rmp_serde::to_vec(self)
1886    }
1887
1888    #[cfg(feature = "fs")]
1889    fn to_uri(&self) -> Result<String, IoError>
1890    where
1891        Self: AsRef<Utf8Path>,
1892    {
1893        Self::URI_PREFIX.cat(self.absolute_utf8()?).ok()
1894    }
1895
1896    #[cfg(feature = "serde")]
1897    fn to_value_from_json_slice<'a, T: Deserialize<'a>>(&'a self) -> Result<T, SerdeJsonError>
1898    where
1899        Self: AsRef<[u8]>,
1900    {
1901        serde_json::from_slice(self.as_ref())
1902    }
1903
1904    #[cfg(feature = "serde")]
1905    fn to_value_from_json_reader<T: DeserializeOwned>(self) -> Result<T, SerdeJsonError>
1906    where
1907        Self: Read + Sized,
1908    {
1909        serde_json::from_reader(self)
1910    }
1911
1912    #[cfg(feature = "rmp")]
1913    fn to_value_from_rmp_slice<'a, T: Deserialize<'a>>(&'a self) -> Result<T, RmpDecodeError>
1914    where
1915        Self: AsRef<[u8]>,
1916    {
1917        rmp_serde::from_slice(self.as_ref())
1918    }
1919
1920    #[cfg(feature = "serde")]
1921    fn to_value_from_value<T: DeserializeOwned>(&self) -> Result<T, SerdeJsonError>
1922    where
1923        Self: Serialize,
1924    {
1925        self.to_json()?.into_value_from_json()
1926    }
1927
1928    #[cfg(feature = "serde")]
1929    fn to_value_from_yaml_slice<'a, T: Deserialize<'a>>(&'a self) -> Result<T, SerdeYamlError>
1930    where
1931        Self: AsRef<[u8]>,
1932    {
1933        serde_yaml_ng::from_slice(self.as_ref())
1934    }
1935
1936    #[cfg(feature = "serde")]
1937    fn to_value_from_yaml_reader<T: DeserializeOwned>(self) -> Result<T, SerdeYamlError>
1938    where
1939        Self: Read + Sized,
1940    {
1941        serde_yaml_ng::from_reader(self)
1942    }
1943
1944    #[cfg(feature = "tui")]
1945    #[must_use]
1946    fn translate_to(&mut self, value: Self) -> Self
1947    where
1948        Self: SaturatingSub,
1949    {
1950        let difference = value.saturating_sub(self);
1951
1952        *self = value;
1953
1954        difference
1955    }
1956
1957    #[cfg(feature = "tui")]
1958    fn transfer(&self, src: &mut Self, dst: &mut Self)
1959    where
1960        Self: SaturatingAdd + SaturatingSub,
1961    {
1962        src.saturating_sub_assign(self);
1963        dst.saturating_add_assign(self);
1964    }
1965
1966    #[cfg(any(feature = "ropey", feature = "tui"))]
1967    #[must_use]
1968    fn transpose(&self) -> Self
1969    where
1970        Self: Transpose + Sized,
1971    {
1972        Transpose::to_transpose(self)
1973    }
1974
1975    fn try_convert<T: TryFrom<Self>>(self) -> Result<T, T::Error>
1976    where
1977        Self: Sized,
1978    {
1979        self.try_into()
1980    }
1981
1982    #[cfg(feature = "async")]
1983    async fn try_join_all<T, E>(self) -> Result<T, E>
1984    where
1985        Self: IntoIterator<Item: TryFuture> + Sized,
1986        T: FromIterator<<Self::Item as TryFuture>::Ok>,
1987        E: From<<Self::Item as TryFuture>::Error>,
1988    {
1989        futures::future::try_join_all(self)
1990            .await?
1991            .into_iter()
1992            .collect::<T>()
1993            .ok()
1994    }
1995
1996    #[cfg(feature = "async")]
1997    async fn try_wait<T, E: 'static + Send + Sync>(self) -> Result<T, AnyhowError>
1998    where
1999        Self: Is<JoinHandle<Result<T, E>>>,
2000        AnyhowError: From<E>,
2001    {
2002        self.into_self().await??.ok()
2003    }
2004
2005    #[must_use]
2006    fn type_name() -> &'static str {
2007        std::any::type_name::<Self>()
2008    }
2009
2010    fn unit(&self) {}
2011
2012    // Future<Option<T>>(). wait_for_some
2013    async fn wait_then_unwrap_or_pending<T>(self) -> T
2014    where
2015        Self: Future<Output = Option<T>> + Sized,
2016    {
2017        match self.await {
2018            Some(value) => value,
2019            None => std::future::pending().await,
2020        }
2021    }
2022
2023    // wait_if_some
2024    async fn unwrap_or_pending_then_wait<F: Future + Unpin>(&mut self) -> F::Output
2025    where
2026        Self: BorrowMut<Option<F>>,
2027    {
2028        if let Some(future) = self.borrow_mut().as_mut() {
2029            future.await
2030        } else {
2031            std::future::pending().await
2032        }
2033    }
2034
2035    fn with<T>(&self, value: T) -> T {
2036        value
2037    }
2038
2039    fn with_item_pushed<T>(self, item: T) -> Vec<T>
2040    where
2041        Self: Is<Vec<T>>,
2042    {
2043        let mut vec = self.into_self();
2044
2045        vec.push(item);
2046
2047        vec
2048    }
2049
2050    fn with_str_pushed(self, rhs: &str) -> String
2051    where
2052        Self: Is<String>,
2053    {
2054        let mut string = self.into_self();
2055
2056        string.push_str(rhs);
2057
2058        string
2059    }
2060
2061    #[cfg(feature = "serde")]
2062    fn write_as_json_to<T: Write>(&self, writer: T) -> Result<(), SerdeJsonError>
2063    where
2064        Self: Serialize,
2065    {
2066        serde_json::to_writer(writer, self)
2067    }
2068
2069    fn write_all_then(&mut self, byte_str: &[u8]) -> Result<&mut Self, IoError>
2070    where
2071        Self: Write,
2072    {
2073        self.write_all(byte_str)?.with(self).ok()
2074    }
2075
2076    #[cfg(any(feature = "async", feature = "process"))]
2077    async fn write_all_then_async(&mut self, byte_str: &[u8]) -> Result<&mut Self, IoError>
2078    where
2079        Self: AsyncWriteExt + Unpin,
2080    {
2081        self.write_all(byte_str).await?.with(self).ok()
2082    }
2083}
2084
2085impl<T: ?Sized> Utils for T {}