1#[cfg(feature = "serde")]
2use crate::as_valuable::AsValuable;
3#[cfg(feature = "fmt")]
4use crate::fmt::{Debugged, OptionalDisplay};
5#[cfg(feature = "ropey")]
6use crate::geometry::PointUsize;
7use crate::is::Is;
8#[cfg(any(feature = "serde", feature = "tui"))]
9use crate::seq_visitor::SeqVisitor;
10#[cfg(feature = "socket")]
11use crate::socket::{Request, Socket};
12#[cfg(feature = "tracing")]
13use crate::status::Status;
14#[cfg(feature = "async")]
15use crate::{into_stream::IntoStream, read_value::ReadValue, run_for::RunForError};
16#[cfg(any(
17 feature = "async",
18 feature = "fs",
19 feature = "process",
20 feature = "reqwest",
21 feature = "socket",
22 feature = "tui",
23))]
24use anyhow::{Context, Error as AnyhowError};
25#[cfg(feature = "async")]
26use bytes::Buf;
27#[cfg(feature = "poem")]
28use bytes::Bytes;
29#[cfg(feature = "fs")]
30use camino::{Utf8Path, Utf8PathBuf};
31#[cfg(any(feature = "async", feature = "poem"))]
32use futures::Stream;
33#[cfg(feature = "async")]
34use futures::{Sink, SinkExt, StreamExt, TryFuture, future::Either, stream::Filter};
35#[cfg(feature = "tui")]
36use num::traits::{SaturatingAdd, SaturatingSub};
37#[cfg(feature = "poem")]
38use poem::{Body as PoemBody, Endpoint, IntoResponse, web::websocket::Message as PoemMessage};
39#[cfg(feature = "poem")]
40use poem_openapi::{error::ParseRequestPayloadError, payload::Binary as PoemBinary, payload::Json as PoemJson};
41#[cfg(feature = "tui")]
42use ratatui::{
43 layout::Rect,
44 text::{Line, Span},
45};
46#[cfg(feature = "reqwest")]
47use reqwest::{RequestBuilder, Response};
48#[cfg(feature = "rmp")]
49use rmp_serde::{decode::Error as RmpDecodeError, encode::Error as RmpEncodeError};
50#[cfg(feature = "ropey")]
51use ropey::{Rope, RopeSlice, iter::Chunks, iter::Lines};
52#[cfg(any(feature = "rmp", feature = "serde", feature = "tui"))]
53use serde::Deserialize;
54#[cfg(any(feature = "serde", feature = "tui"))]
55use serde::Deserializer;
56#[cfg(any(feature = "reqwest", feature = "rmp", feature = "serde"))]
57use serde::Serialize;
58#[cfg(feature = "serde")]
59use serde::de::DeserializeOwned;
60#[cfg(any(feature = "poem", feature = "serde"))]
61use serde_json::Error as SerdeJsonError;
62#[cfg(feature = "serde")]
63use serde_json::{Value as Json, value::Index};
64#[cfg(feature = "serde")]
65use serde_yaml_ng::Error as SerdeYamlError;
66use std::{
67 borrow::{Borrow, BorrowMut, Cow},
68 collections::HashMap,
69 error::Error as StdError,
70 fmt::Display,
71 fs::File,
72 future::Ready,
73 hash::Hash,
74 io::{BufReader, BufWriter, Error as IoError, Read, Write},
75 iter::{Once, Repeat},
76 mem::ManuallyDrop,
77 ops::{Add, ControlFlow, Range},
78 path::Path,
79 pin::Pin,
80 str::Utf8Error,
81 sync::{
82 Arc,
83 atomic::{AtomicUsize, Ordering},
84 },
85 task::Poll,
86 time::Instant,
87};
88#[cfg(feature = "fs")]
89use std::{fmt::Debug, path::PathBuf};
90#[cfg(feature = "async")]
91use std::{fs::Metadata, time::Duration};
92#[cfg(any(feature = "async", feature = "ropey"))]
93use tokio::{
94 fs::File as TokioFile,
95 io::{AsyncRead, BufReader as TokioBufReader},
96};
97#[cfg(feature = "async")]
98use tokio::{
99 io::{AsyncReadExt, AsyncWrite, AsyncWriteExt, BufWriter as TokioBufWriter},
100 sync::oneshot::Sender as OneshotSender,
101 task::JoinHandle,
102 task::{JoinSet, LocalSet},
103 time::{Interval, Sleep, Timeout},
104};
105#[cfg(feature = "async")]
106use tokio_util::{
107 codec::{Framed, LengthDelimitedCodec, LinesCodec},
108 io::StreamReader,
109};
110#[cfg(feature = "tracing")]
111use tracing::Level;
112#[cfg(any(feature = "ropey", feature = "tui"))]
113use unicode_segmentation::{Graphemes, UnicodeSegmentation};
114#[cfg(feature = "serde")]
115use valuable::Value;
116
117#[allow(async_fn_in_trait)]
118pub trait Utils {
119 const NEWLINE: &str = "\n";
120
121 #[cfg(feature = "async")]
122 async fn abort_all_and_wait<T: 'static>(&mut self)
123 where
124 Self: BorrowMut<JoinSet<T>>,
125 {
126 let join_set = self.borrow_mut();
127
128 join_set.abort_all();
129
130 while join_set.join_next().await.is_some() {}
131 }
132
133 #[cfg(feature = "fs")]
134 fn absolute_utf8(&self) -> Result<Cow<'_, Utf8Path>, IoError>
135 where
136 Self: AsRef<Utf8Path>,
137 {
138 let path = self.as_ref();
139
140 if path.is_absolute() {
141 path.borrowed().ok()
142 } else {
143 camino::absolute_utf8(path)?.owned::<Utf8Path>().ok()
144 }
145 }
146
147 async fn achain<T: Future>(self, rhs: T) -> T::Output
148 where
149 Self: Future + Sized,
150 {
151 self.await;
152
153 rhs.await
154 }
155
156 #[cfg(feature = "tui")]
157 fn add_span<'a, T: Into<Span<'a>>>(self, span: T) -> Line<'a>
158 where
159 Self: Into<Line<'a>>,
160 {
161 let mut line = self.into();
162
163 line.spans.push(span.into());
164
165 line
166 }
167
168 #[cfg(any(
169 feature = "async",
170 feature = "fs",
171 feature = "process",
172 feature = "reqwest",
173 feature = "socket",
174 feature = "tui",
175 ))]
176 fn anyhow_result<T, E: Into<AnyhowError>>(self) -> Result<T, AnyhowError>
177 where
178 Self: Is<Result<T, E>>,
179 {
180 self.into_self().map_err(E::into)
181 }
182
183 fn arc(self) -> Arc<Self>
184 where
185 Self: Sized,
186 {
187 Arc::new(self)
188 }
189
190 async fn async_with<T>(self, next: impl Future<Output = T>) -> T
191 where
192 Self: Future + Sized,
193 {
194 self.await;
195
196 next.await
197 }
198
199 fn as_borrowed<'a, B: ?Sized + ToOwned>(&'a self) -> &'a B
200 where
201 Self: Borrow<Cow<'a, B>>,
202 {
203 self.borrow().borrow()
204 }
205
206 fn as_ptr(&self) -> *const Self {
207 std::ptr::from_ref(self)
208 }
209
210 fn as_ptr_mut(&mut self) -> *mut Self {
211 std::ptr::from_mut(self)
212 }
213
214 fn as_utf8(&self) -> Result<&str, Utf8Error>
215 where
216 Self: AsRef<[u8]>,
217 {
218 std::str::from_utf8(self.as_ref())
219 }
220
221 #[cfg(feature = "fs")]
222 fn as_utf8_path(&self) -> &Utf8Path
223 where
224 Self: AsRef<Utf8Path>,
225 {
226 self.as_ref()
227 }
228
229 #[cfg(feature = "ropey")]
230 fn as_slice(&self) -> RopeSlice<'_>
231 where
232 Self: Borrow<Rope>,
233 {
234 self.borrow().slice(..)
235 }
236
237 #[cfg(feature = "serde")]
238 fn as_valuable(&self) -> Value<'_>
239 where
240 Self: AsValuable,
241 {
242 AsValuable::as_valuable(self)
243 }
244
245 fn borrowed(&self) -> Cow<'_, Self>
246 where
247 Self: ToOwned,
248 {
249 Cow::Borrowed(self)
250 }
251
252 fn buf_reader(self) -> BufReader<Self>
253 where
254 Self: Read + Sized,
255 {
256 BufReader::new(self)
257 }
258
259 #[cfg(any(feature = "async", feature = "ropey"))]
260 fn buf_reader_async(self) -> TokioBufReader<Self>
261 where
262 Self: AsyncRead + Sized,
263 {
264 TokioBufReader::new(self)
265 }
266
267 fn buf_writer(self) -> BufWriter<Self>
268 where
269 Self: Write + Sized,
270 {
271 BufWriter::new(self)
272 }
273
274 #[cfg(feature = "async")]
275 fn buf_writer_async(self) -> TokioBufWriter<Self>
276 where
277 Self: AsyncWrite + Sized,
278 {
279 TokioBufWriter::new(self)
280 }
281
282 fn cast_ref<T>(&self) -> &T {
285 let ptr = std::ptr::from_ref(self).cast::<T>();
286 let value = unsafe { ptr.as_ref() };
287
288 value.unwrap()
289 }
290
291 fn cat<T: Display>(&self, rhs: T) -> String
292 where
293 Self: Display,
294 {
295 std::format!("{self}{rhs}")
296 }
297
298 #[cfg(any(
299 feature = "async",
300 feature = "fs",
301 feature = "process",
302 feature = "reqwest",
303 feature = "socket",
304 feature = "tui",
305 ))]
306 fn check_next<T>(self) -> Result<T, AnyhowError>
307 where
308 Self: Is<Option<T>>,
309 {
310 match self.into_self() {
311 Some(item) => item.ok(),
312 None => anyhow::bail!(
313 "sequence of {type_name} items is exhausted",
314 type_name = Self::type_name(),
315 ),
316 }
317 }
318
319 #[cfg(any(
320 feature = "async",
321 feature = "fs",
322 feature = "process",
323 feature = "reqwest",
324 feature = "socket",
325 feature = "tui",
326 ))]
327 fn check_present<T>(self) -> Result<T, AnyhowError>
328 where
329 Self: Is<Option<T>>,
330 {
331 match self.into_self() {
332 Some(item) => item.ok(),
333 None => anyhow::bail!(
334 "keyed entry of type {type_name} is not present in the collection",
335 type_name = Self::type_name(),
336 ),
337 }
338 }
339
340 #[cfg(feature = "reqwest")]
342 async fn check_status(self) -> Result<Response, AnyhowError>
343 where
344 Self: Is<Response>,
345 {
346 let response = self.into_self();
347 let status = response.status();
348
349 if !status.is_client_error() && !status.is_server_error() {
350 return response.ok();
351 }
352
353 let text = match response.text().await {
354 Ok(text) => text,
355 Err(error) => std::format!("unable to read response text: {error}"),
356 };
357
358 anyhow::bail!("({status}) {text}")
359 }
360
361 fn convert<T: From<Self>>(self) -> T
362 where
363 Self: Sized,
364 {
365 self.into()
366 }
367
368 fn find_eq<Q, K>(&self, query: Q) -> Option<(usize, &K)>
369 where
370 Self: AsRef<[K]>,
371 for<'a> &'a K: PartialEq<Q>,
372 {
373 self.as_ref().iter().enumerate().find(|(_index, key)| *key == query)
374 }
375
376 fn contains_eq<Q, K>(&self, query: Q) -> bool
377 where
378 Self: AsRef<[K]>,
379 for<'a> &'a K: PartialEq<Q>,
380 {
381 self.find_eq(query).is_some()
382 }
383
384 #[cfg(any(
385 feature = "async",
386 feature = "fs",
387 feature = "process",
388 feature = "reqwest",
389 feature = "socket",
390 feature = "tui",
391 ))]
392 fn context_path<T, E, C: 'static + Display + Send + Sync, P: AsRef<Path>>(
393 self,
394 context: C,
395 path: P,
396 ) -> Result<T, AnyhowError>
397 where
398 Self: Context<T, E> + Sized,
399 {
400 let context = std::format!("{context}: {path}", path = path.as_ref().display());
401
402 self.context(context)
403 }
404
405 fn create(&self) -> Result<File, IoError>
406 where
407 Self: AsRef<Path>,
408 {
409 File::create(self)
410 }
411
412 fn create_dir_all(&self) -> Result<(), IoError>
413 where
414 Self: AsRef<Path>,
415 {
416 std::fs::create_dir_all(self)
417 }
418
419 #[cfg(feature = "fmt")]
420 fn debug(&self) -> Debugged<'_, Self> {
421 Debugged::new(self)
422 }
423
424 #[cfg(any(feature = "serde", feature = "tui"))]
425 fn deserialize_from_seq<'de, D: Deserializer<'de>, X: Deserialize<'de>, Y, E: Display, F: Fn(X) -> Result<Y, E>>(
426 deserializer: D,
427 func: F,
428 ) -> Result<Self, D::Error>
429 where
430 Self: Default + Extend<Y>,
431 {
432 let seq_visitor = SeqVisitor::new(func);
433
434 deserializer.deserialize_seq(seq_visitor)
435 }
436
437 fn err<T>(self) -> Result<T, Self>
438 where
439 Self: Sized,
440 {
441 Err(self)
442 }
443
444 #[cfg(feature = "fs")]
445 fn expand_user(&self) -> Cow<'_, Utf8Path>
446 where
447 Self: AsRef<str>,
448 {
449 let path_str = self.as_ref();
450
451 if let Some(relative_path_str) = path_str.strip_prefix("~/")
452 && let Some(home_dirpath) = Self::home_dirpath()
453 {
454 home_dirpath.join(relative_path_str).owned()
455 } else {
456 path_str.as_utf8_path().borrowed()
457 }
458 }
459
460 #[cfg(feature = "fs")]
461 fn unexpand_user(&self) -> Cow<'_, Utf8Path>
462 where
463 Self: AsRef<str>,
464 {
465 let path_str = self.as_ref();
466
467 if let Some(home_dirpath) = Self::home_dirpath()
468 && let Some(relative_path_str) = path_str.strip_prefix(home_dirpath.as_str())
469 {
470 if relative_path_str.is_empty() {
471 "~".convert::<Utf8PathBuf>().owned()
472 } else if relative_path_str.as_utf8_path().is_absolute() {
473 "~".cat(relative_path_str).convert::<Utf8PathBuf>().owned()
474 } else {
475 path_str.as_utf8_path().borrowed()
476 }
477 } else {
478 path_str.as_utf8_path().borrowed()
479 }
480 }
481
482 #[cfg(any(feature = "ropey", feature = "tui"))]
483 fn extended_graphemes(&self) -> Graphemes<'_>
484 where
485 Self: AsRef<str>,
486 {
487 self.as_ref().graphemes(true)
488 }
489
490 #[cfg(feature = "ropey")]
491 fn extended_graphemes_at<'a>(self, extended_graphemes_index_range: Range<usize>) -> impl Iterator<Item = &'a str>
492 where
493 Self: Is<RopeSlice<'a>>,
494 {
495 let extended_graphemes_index_range = extended_graphemes_index_range.borrow();
496
497 self.into_self()
498 .chunks()
499 .flat_map(str::extended_graphemes)
500 .skip(extended_graphemes_index_range.start)
501 .take(extended_graphemes_index_range.len())
502 }
503
504 #[cfg(feature = "ropey")]
505 fn extended_graphemes_at_rect<'a>(
506 self,
507 lines_index_range: Range<usize>,
508 extended_graphemes_index_range: Range<usize>,
509 ) -> impl Iterator<Item = impl Iterator<Item = &'a str>>
510 where
511 Self: Is<RopeSlice<'a>>,
512 {
513 self.into_self()
514 .saturating_lines_at(lines_index_range.start)
515 .take(lines_index_range.len())
516 .map(move |line_rope_slice| line_rope_slice.extended_graphemes_at(extended_graphemes_index_range.clone()))
517 }
518
519 #[cfg(feature = "async")]
520 fn filter_sync(
521 self,
522 mut func: impl FnMut(&Self::Item) -> bool,
523 ) -> Filter<Self, Ready<bool>, impl FnMut(&Self::Item) -> Ready<bool>>
524 where
525 Self: Sized + StreamExt,
526 {
527 self.filter(move |x| func(x).ready())
529 }
530
531 #[cfg(feature = "fs")]
532 fn file_name_ok(&self) -> Result<&str, AnyhowError>
533 where
534 Self: AsRef<Utf8Path>,
535 {
536 self.as_ref().file_name().context("path has no file name")
537 }
538
539 fn has_happened(self) -> bool
540 where
541 Self: Is<Instant>,
542 {
543 self.into_self() <= Instant::now()
544 }
545
546 #[cfg(feature = "fs")]
547 #[must_use]
548 fn home_dirpath() -> Option<Utf8PathBuf> {
549 home::home_dir()?.try_convert::<Utf8PathBuf>().ok()
550 }
551
552 fn if_else<T>(self, true_value: T, false_value: T) -> T
553 where
554 Self: Is<bool>,
555 {
556 if self.into_self() { true_value } else { false_value }
557 }
558
559 fn immutable(&mut self) -> &Self {
560 self
561 }
562
563 fn inc(&self) -> usize
564 where
565 Self: Borrow<AtomicUsize>,
566 {
567 self.borrow().fetch_add(1, Ordering::SeqCst)
568 }
569
570 fn insert_mut<'a, K: 'a + Eq + Hash, V>(&'a mut self, key: K, value: V) -> &'a mut V
571 where
572 Self: BorrowMut<HashMap<K, V>>,
573 {
574 self.borrow_mut().entry(key).insert_entry(value).into_mut()
575 }
576
577 fn into_break<C>(self) -> ControlFlow<Self, C>
578 where
579 Self: Sized,
580 {
581 ControlFlow::Break(self)
582 }
583
584 fn into_continue<B>(self) -> ControlFlow<B, Self>
585 where
586 Self: Sized,
587 {
588 ControlFlow::Continue(self)
589 }
590
591 #[cfg(feature = "poem")]
592 fn into_endpoint(self) -> impl Endpoint<Output = Self>
593 where
594 Self: Clone + IntoResponse + Sync,
595 {
596 let func = move |_request| self.clone();
597
598 poem::endpoint::make_sync(func)
599 }
600
601 #[cfg(feature = "async")]
602 fn into_interval(self) -> Interval
603 where
604 Self: Is<Duration>,
605 {
606 tokio::time::interval(self.into_self())
607 }
608
609 #[cfg(feature = "async")]
610 fn into_left<R>(self) -> Either<Self, R>
611 where
612 Self: Sized,
613 {
614 Either::Left(self)
615 }
616
617 #[cfg(feature = "tui")]
618 fn into_line<'a>(self) -> Line<'a>
619 where
620 Self: Into<Cow<'a, str>>,
621 {
622 self.into().into()
623 }
624
625 fn into_manually_drop(self) -> ManuallyDrop<Self>
626 where
627 Self: Sized,
628 {
629 ManuallyDrop::new(self)
630 }
631
632 #[cfg(feature = "async")]
633 fn into_stream_reader<B: Buf, E: Into<IoError>>(self) -> StreamReader<Self, B>
634 where
635 Self: Sized + Stream<Item = Result<B, E>>,
636 {
637 StreamReader::new(self)
638 }
639
640 #[cfg(feature = "async")]
641 fn into_length_delimited_frames(self) -> Framed<Self, LengthDelimitedCodec>
642 where
643 Self: Sized,
644 {
645 Framed::new(self, LengthDelimitedCodec::new())
646 }
647
648 #[cfg(feature = "async")]
649 fn into_line_frames(self) -> Framed<Self, LinesCodec>
650 where
651 Self: Sized,
652 {
653 Framed::new(self, LinesCodec::new())
654 }
655
656 #[cfg(feature = "async")]
657 fn into_right<L>(self) -> Either<L, Self>
658 where
659 Self: Sized,
660 {
661 Either::Right(self)
662 }
663
664 #[cfg(feature = "poem")]
666 fn into_parse_request_payload_result<T>(self) -> Result<T, ParseRequestPayloadError>
667 where
668 Self: Is<Result<T, SerdeJsonError>>,
669 {
670 match self.into_self() {
671 Ok(value) => value.ok(),
672 Err(serde_json_error) => ParseRequestPayloadError {
673 reason: serde_json_error.to_string(),
674 }
675 .err(),
676 }
677 }
678
679 #[cfg(feature = "async")]
680 async fn into_select<T: Future>(self, rhs: T) -> Either<Self::Output, T::Output>
681 where
682 Self: Future + Sized,
683 {
684 tokio::select! {
685 value = self => value.into_left(),
686 value = rhs => value.into_right(),
687 }
688 }
689
690 #[cfg(feature = "tracing")]
691 fn into_status<T, E>(self) -> Status<T, E>
692 where
693 Self: Is<Result<T, E>>,
694 {
695 Status::new(self.into_self())
696 }
697
698 #[cfg(feature = "async")]
699 fn into_stream(self) -> Self::Stream
700 where
701 Self: IntoStream + Sized,
702 {
703 IntoStream::into_stream(self)
704 }
705
706 #[cfg(feature = "fs")]
707 fn into_string(self) -> Result<String, AnyhowError>
708 where
709 Self: Is<PathBuf>,
710 {
711 match self.into_self().into_os_string().into_string() {
712 Ok(string) => string.ok(),
713 Err(os_string) => os_string.invalid_utf8_err(),
714 }
715 }
716
717 #[cfg(feature = "serde")]
718 fn into_value_from_json<T: DeserializeOwned>(self) -> Result<T, SerdeJsonError>
719 where
720 Self: Is<Json>,
721 {
722 serde_json::from_value(self.into_self())
723 }
724
725 #[cfg(feature = "fs")]
726 fn invalid_utf8_err<T>(&self) -> Result<T, AnyhowError>
727 where
728 Self: Debug,
729 {
730 anyhow::bail!("{self:?} is not valid utf-8")
731 }
732
733 fn io_error(self) -> IoError
734 where
735 Self: Into<Box<dyn StdError + Send + Sync>>,
736 {
737 IoError::other(self)
738 }
739
740 fn io_result<T, E: Into<Box<dyn StdError + Send + Sync>>>(self) -> Result<T, IoError>
741 where
742 Self: Is<Result<T, E>>,
743 {
744 self.into_self().map_err(E::io_error)
745 }
746
747 #[cfg(feature = "async")]
748 async fn join_all<T>(self) -> T
749 where
750 Self: IntoIterator<Item: Future> + Sized,
751 T: FromIterator<<Self::Item as Future>::Output>,
752 {
753 futures::future::join_all(self).await.into_iter().collect()
754 }
755
756 #[cfg(any(feature = "ropey", feature = "tui"))]
757 fn len_extended_graphemes(&self) -> usize
758 where
759 Self: AsRef<str>,
760 {
761 self.as_ref().extended_graphemes().count()
762 }
763
764 #[cfg(feature = "tracing")]
765 fn level<T, E>(&self) -> Level
766 where
767 Self: Borrow<Result<T, E>>,
768 {
769 if self.borrow().is_ok() {
770 Level::INFO
771 } else {
772 Level::WARN
773 }
774 }
775
776 #[cfg(any(feature = "tui", feature = "tracing"))]
777 fn log_error(&self)
778 where
779 Self: Display,
780 {
781 tracing::warn!(error = %self, "error: {self:#}");
782 }
783
784 #[cfg(any(feature = "tui", feature = "tracing"))]
785 #[must_use]
786 fn log_if_error<T, E: Display>(self) -> Self
787 where
788 Self: Borrow<Result<T, E>> + Sized,
789 {
790 if let Err(error) = self.borrow() {
791 error.log_error();
792 }
793
794 self
795 }
796
797 fn map_collect<Y, T: FromIterator<Y>>(self, func: impl FnMut(Self::Item) -> Y) -> T
798 where
799 Self: IntoIterator + Sized,
800 {
801 self.into_iter().map(func).collect::<T>()
802 }
803
804 fn map_into<Y, X: Into<Y>>(self) -> Option<Y>
805 where
806 Self: Is<Option<X>>,
807 {
808 self.into_self().map(X::into)
809 }
810
811 fn map_as_ref<'a, Y: ?Sized, X: 'a + AsRef<Y>>(&'a self) -> Option<&'a Y>
812 where
813 Self: Borrow<Option<X>>,
814 {
815 self.borrow().as_ref().map(X::as_ref)
816 }
817
818 fn mem_drop(self)
819 where
820 Self: Sized,
821 {
822 std::mem::drop(self);
823 }
824
825 #[must_use]
826 fn mem_take(&mut self) -> Self
827 where
828 Self: Default,
829 {
830 std::mem::take(self)
831 }
832
833 #[cfg(feature = "async")]
834 async fn metadata_async(&self) -> Result<Metadata, IoError>
835 where
836 Self: AsRef<Path>,
837 {
838 tokio::fs::metadata(self).await
839 }
840
841 #[cfg(feature = "ropey")]
842 fn num_lines_and_extended_graphemes<'a>(self) -> PointUsize
843 where
844 Self: Is<RopeSlice<'a>>,
845 {
846 let rope_slice = self.into_self();
847 let y = rope_slice.len_lines();
848 let x = rope_slice
849 .lines()
850 .map(|line_rope| line_rope.chunks().map(str::len_extended_graphemes).sum())
851 .max()
852 .unwrap_or(0);
853
854 PointUsize::new(x, y)
855 }
856
857 fn ok<E>(self) -> Result<Self, E>
858 where
859 Self: Sized,
860 {
861 Ok(self)
862 }
863
864 fn once(self) -> Once<Self>
865 where
866 Self: Sized,
867 {
868 std::iter::once(self)
869 }
870
871 fn open(&self) -> Result<File, IoError>
872 where
873 Self: AsRef<Path>,
874 {
875 File::open(self)
876 }
877
878 #[cfg(any(feature = "ropey", feature = "async"))]
879 async fn open_async(&self) -> Result<TokioFile, IoError>
880 where
881 Self: AsRef<Path>,
882 {
883 TokioFile::open(self).await
884 }
885
886 #[cfg(feature = "fmt")]
887 fn optional_display(&self) -> OptionalDisplay<'_, Self> {
888 OptionalDisplay::new(self)
889 }
890
891 fn owned<B: ?Sized + ToOwned<Owned = Self>>(self) -> Cow<'static, B>
892 where
893 Self: Sized,
894 {
895 Cow::Owned(self)
896 }
897
898 fn pair<T>(self, rhs: T) -> (Self, T)
899 where
900 Self: Sized,
901 {
902 (self, rhs)
903 }
904
905 fn pin(self) -> Pin<Box<Self>>
906 where
907 Self: Sized,
908 {
909 Box::pin(self)
910 }
911
912 fn pipe<X, Y, Z, F: FnMut(Y) -> Z>(mut self, mut func: F) -> impl FnMut(X) -> Z
913 where
914 Self: Sized + FnMut(X) -> Y,
915 {
916 move |x| self(x).pipe_into(&mut func)
917 }
918
919 fn poll_ready(self) -> Poll<Self>
920 where
921 Self: Sized,
922 {
923 Poll::Ready(self)
924 }
925
926 fn pipe_into<T, F: FnOnce(Self) -> T>(self, func: F) -> T
927 where
928 Self: Sized,
929 {
930 func(self)
931 }
932
933 #[cfg(feature = "poem")]
934 fn poem_binary(self) -> PoemBinary<Self>
935 where
936 Self: Sized,
937 {
938 PoemBinary(self)
939 }
940
941 #[cfg(feature = "poem")]
942 fn poem_binary_message(self) -> PoemMessage
943 where
944 Self: Is<Vec<u8>>,
945 {
946 PoemMessage::Binary(self.into_self())
947 }
948
949 #[cfg(feature = "poem")]
950 fn poem_json(self) -> PoemJson<Self>
951 where
952 Self: Sized,
953 {
954 PoemJson(self)
955 }
956
957 #[cfg(feature = "poem")]
958 fn poem_stream_body<O: 'static + Into<Bytes>, E: 'static + Into<IoError>>(self) -> PoemBinary<PoemBody>
959 where
960 Self: 'static + Send + Sized + Stream<Item = Result<O, E>>,
961 {
962 PoemBody::from_bytes_stream(self).poem_binary()
963 }
964
965 #[cfg(feature = "poem")]
966 fn poem_text_message(self) -> PoemMessage
967 where
968 Self: Is<String>,
969 {
970 PoemMessage::Text(self.into_self())
971 }
972
973 fn println(&self)
974 where
975 Self: Display,
976 {
977 std::println!("{self}");
978 }
979
980 fn print(&self)
981 where
982 Self: Display,
983 {
984 std::print!("{self}");
985 }
986
987 fn push_to<T: Extend<Self>>(self, collection: &mut T)
988 where
989 Self: Sized,
990 {
991 collection.extend(self.once());
992 }
993
994 #[cfg(feature = "reqwest")]
995 fn query_all<T: Serialize>(self, name: &str, values: impl IntoIterator<Item = T>) -> RequestBuilder
996 where
997 Self: Is<RequestBuilder>,
998 {
999 let mut request_builder = self.into_self();
1000
1001 for value in values {
1002 request_builder = request_builder.query_one(name, value);
1003 }
1004
1005 request_builder
1006 }
1007
1008 #[cfg(feature = "reqwest")]
1009 fn query_one<T: Serialize>(self, name: &str, value: impl Into<Option<T>>) -> RequestBuilder
1010 where
1011 Self: Is<RequestBuilder>,
1012 {
1013 let query: &[(&str, T)] = if let Some(value) = value.into() {
1014 &[(name, value)]
1015 } else {
1016 &[]
1017 };
1018 let request_builder = self.into_self();
1019
1020 request_builder.query(query)
1021 }
1022
1023 fn range_from_len<T: Add<Output = T> + Copy>(self, len: impl Into<T>) -> Range<T>
1024 where
1025 Self: Into<T>,
1026 {
1027 let start = self.into();
1028 let end = start + len.into();
1029
1030 start..end
1031 }
1032
1033 #[cfg(feature = "tui")]
1034 fn ratatui_rect(self) -> Rect
1035 where
1036 Self: Into<(u16, u16)>,
1037 {
1038 let (width, height) = self.into();
1039 let x = 0;
1040 let y = 0;
1041
1042 Rect { x, y, width, height }
1043 }
1044
1045 #[cfg(feature = "async")]
1046 async fn read_string_async(&mut self) -> Result<String, IoError>
1047 where
1048 Self: AsyncReadExt + Unpin,
1049 {
1050 let mut string = String::new();
1051
1052 self.read_to_string(&mut string).await?;
1053
1054 string.ok()
1055 }
1056
1057 #[cfg(feature = "async")]
1058 async fn read_to_string_async(self) -> ReadValue<Self>
1059 where
1060 Self: AsRef<Path> + Sized,
1061 {
1062 let result = tokio::fs::read_to_string(self.as_ref()).await;
1063
1064 ReadValue::new(self, result)
1065 }
1066
1067 #[cfg(feature = "async")]
1068 async fn read_to_string_else_stdin_async<P: AsRef<Path>>(self) -> ReadValue<Option<P>>
1069 where
1070 Self: Is<Option<P>> + Sized,
1071 {
1072 if let Some(filepath) = self.into_self() {
1073 tokio::fs::read_to_string(filepath.as_ref()).await.pair(filepath.some())
1074 } else {
1075 tokio::io::stdin()
1076 .buf_reader_async()
1077 .read_string_async()
1078 .await
1079 .pair(None)
1080 }
1081 .reversed()
1082 .into()
1083 }
1084
1085 fn ready(self) -> Ready<Self>
1086 where
1087 Self: Sized,
1088 {
1089 std::future::ready(self)
1090 }
1091
1092 fn repeat(self) -> Repeat<Self>
1093 where
1094 Self: Clone,
1095 {
1096 std::iter::repeat(self)
1097 }
1098
1099 fn reversed<X, Y>(self) -> (Y, X)
1100 where
1101 Self: Is<(X, Y)>,
1102 {
1103 let (x, y) = self.into_self();
1104
1105 y.pair(x)
1106 }
1107
1108 #[cfg(feature = "async")]
1109 async fn run_for(mut self, duration: Duration) -> Result<Self, RunForError<Self::Output>>
1110 where
1111 Self: Future + Sized + Unpin,
1112 {
1113 tokio::select! {
1114 output = &mut self => RunForError::new(output).err(),
1115 () = tokio::time::sleep(duration) => self.ok(),
1116 }
1117 }
1118
1119 #[cfg(feature = "async")]
1120 async fn run_local(self) -> Self::Output
1121 where
1122 Self: Future + Sized,
1123 {
1124 LocalSet::new().run_until(self).await
1125 }
1126
1127 fn remove_file(&self) -> Result<(), IoError>
1128 where
1129 Self: AsRef<Path>,
1130 {
1131 std::fs::remove_file(self)
1132 }
1133
1134 #[cfg(feature = "socket")]
1135 async fn respond_to<T: Request<Response = Self>>(
1136 &self,
1137 mut socket: impl BorrowMut<Socket>,
1138 ) -> Result<(), AnyhowError> {
1139 socket.borrow_mut().respond::<T>(self).await
1140 }
1141
1142 #[cfg(feature = "ropey")]
1146 fn saturating_chunks_at_extended_grapheme<'a>(self, extended_grapheme_index: usize) -> Chunks<'a>
1147 where
1148 Self: Is<RopeSlice<'a>>,
1149 {
1150 self.saturating_chunks_at_char(extended_grapheme_index)
1151 }
1152
1153 #[cfg(feature = "ropey")]
1155 fn saturating_chunks_at_char<'a>(self, char_index: usize) -> Chunks<'a>
1156 where
1157 Self: Is<RopeSlice<'a>>,
1158 {
1159 let rope_slice = self.into_self();
1160 let char_index = rope_slice.len_chars().min(char_index);
1161
1162 rope_slice.chunks_at_char(char_index).0
1163 }
1164
1165 #[cfg(feature = "ropey")]
1167 fn saturating_lines_at<'a>(self, line_index: usize) -> Lines<'a>
1168 where
1169 Self: Is<RopeSlice<'a>>,
1170 {
1171 let rope_slice = self.into_self();
1172 let line_index = rope_slice.len_lines().min(line_index);
1173
1174 rope_slice.lines_at(line_index)
1175 }
1176
1177 #[cfg(feature = "tui")]
1178 fn saturating_add_or_sub_in_place_with_max(&mut self, rhs: Self, max_value: Self, add: bool)
1179 where
1180 Self: Ord + SaturatingAdd + SaturatingSub + Sized,
1181 {
1182 let value = if add {
1183 self.saturating_add(&rhs)
1184 } else {
1185 self.saturating_sub(&rhs)
1186 };
1187
1188 *self = value.min(max_value);
1189 }
1190
1191 #[cfg(feature = "async")]
1192 async fn send_to<T: Sink<Self> + Unpin>(self, mut sink: T) -> Result<(), T::Error>
1193 where
1194 Self: Sized,
1195 {
1196 sink.send(self).await
1197 }
1198
1199 #[cfg(feature = "async")]
1200 fn send_to_oneshot(self, sender: OneshotSender<Self>) -> Result<(), AnyhowError>
1201 where
1202 Self: Sized,
1203 {
1204 sender
1206 .send(self)
1207 .ok()
1208 .context("unable to send value over oneshot channel")
1209 }
1210
1211 #[cfg(feature = "async")]
1212 fn sleep(self) -> Sleep
1213 where
1214 Self: Is<Duration>,
1215 {
1216 tokio::time::sleep(self.into_self())
1217 }
1218
1219 fn some(self) -> Option<Self>
1220 where
1221 Self: Sized,
1222 {
1223 Some(self)
1224 }
1225
1226 #[cfg(feature = "async")]
1227 fn spawn_task(self) -> JoinHandle<Self::Output>
1228 where
1229 Self: 'static + Future + Sized + Send,
1230 Self::Output: 'static + Send,
1231 {
1232 tokio::spawn(self)
1233 }
1234
1235 fn substr_interval(&self, query: &[u8]) -> Option<(usize, usize)>
1237 where
1238 Self: AsRef<[u8]>,
1239 {
1240 let bytes = self.as_ref();
1241 let predicate = |substr| substr == query;
1242 let query_len = query.len();
1243 let begin = bytes.windows(query_len).position(predicate)?;
1244 let end = begin + query_len;
1245
1246 (begin, end).some()
1247 }
1248
1249 #[cfg(feature = "serde")]
1250 fn take_json<T: DeserializeOwned>(&mut self, index: impl Index) -> Result<T, SerdeJsonError>
1251 where
1252 Self: BorrowMut<Json>,
1253 {
1254 self.borrow_mut()
1255 .get_mut(index)
1256 .unwrap_or(&mut Json::Null)
1257 .mem_take()
1258 .into_value_from_json()
1259 }
1260
1261 #[cfg(feature = "async")]
1262 fn timeout(self, duration: Duration) -> Timeout<Self>
1263 where
1264 Self: Future + Sized,
1265 {
1266 tokio::time::timeout(duration, self)
1267 }
1268
1269 fn toggle(&mut self)
1270 where
1271 Self: BorrowMut<bool>,
1272 {
1273 let bool_value = self.borrow_mut();
1274
1275 *bool_value = !*bool_value;
1276 }
1277
1278 #[cfg(feature = "serde")]
1279 fn to_json(&self) -> Result<Json, SerdeJsonError>
1280 where
1281 Self: Serialize,
1282 {
1283 serde_json::to_value(self)
1284 }
1285
1286 #[cfg(feature = "serde")]
1287 fn to_json_byte_str(&self) -> Result<Vec<u8>, SerdeJsonError>
1288 where
1289 Self: Serialize,
1290 {
1291 serde_json::to_vec(self)
1292 }
1293
1294 #[cfg(feature = "serde")]
1295 fn to_json_object(&self, key: &str) -> Json
1296 where
1297 Self: Serialize,
1298 {
1299 serde_json::json!({key: self})
1300 }
1301
1302 #[cfg(feature = "serde")]
1303 fn to_json_str(&self) -> Result<String, SerdeJsonError>
1304 where
1305 Self: Serialize,
1306 {
1307 serde_json::to_string(self)
1308 }
1309
1310 #[cfg(feature = "rmp")]
1311 fn to_rmp_byte_str(&self) -> Result<Vec<u8>, RmpEncodeError>
1312 where
1313 Self: Serialize,
1314 {
1315 rmp_serde::to_vec(self)
1316 }
1317
1318 #[cfg(feature = "fs")]
1319 fn to_uri(&self) -> Result<String, IoError>
1320 where
1321 Self: AsRef<Utf8Path>,
1322 {
1323 "file://".cat(self.absolute_utf8()?).ok()
1324 }
1325
1326 #[cfg(feature = "serde")]
1327 fn to_value_from_json_slice<'a, T: Deserialize<'a>>(&'a self) -> Result<T, SerdeJsonError>
1328 where
1329 Self: AsRef<[u8]>,
1330 {
1331 serde_json::from_slice(self.as_ref())
1332 }
1333
1334 #[cfg(feature = "serde")]
1335 fn to_value_from_yaml_slice<'a, T: Deserialize<'a>>(&'a self) -> Result<T, SerdeYamlError>
1336 where
1337 Self: AsRef<[u8]>,
1338 {
1339 serde_yaml_ng::from_slice(self.as_ref())
1340 }
1341
1342 #[cfg(feature = "serde")]
1343 fn to_value_from_json_reader<T: DeserializeOwned>(self) -> Result<T, SerdeJsonError>
1344 where
1345 Self: Read + Sized,
1346 {
1347 serde_json::from_reader(self)
1348 }
1349
1350 #[cfg(feature = "rmp")]
1351 fn to_value_from_rmp_slice<'a, T: Deserialize<'a>>(&'a self) -> Result<T, RmpDecodeError>
1352 where
1353 Self: AsRef<[u8]>,
1354 {
1355 rmp_serde::from_slice(self.as_ref())
1356 }
1357
1358 #[cfg(feature = "serde")]
1359 fn to_value_from_value<T: DeserializeOwned>(&self) -> Result<T, SerdeJsonError>
1360 where
1361 Self: Serialize,
1362 {
1363 self.to_json()?.into_value_from_json()
1364 }
1365
1366 fn try_convert<T: TryFrom<Self>>(self) -> Result<T, T::Error>
1367 where
1368 Self: Sized,
1369 {
1370 self.try_into()
1371 }
1372
1373 #[cfg(feature = "async")]
1374 async fn try_join_all<T, E>(self) -> Result<T, E>
1375 where
1376 Self: IntoIterator<Item: TryFuture> + Sized,
1377 T: FromIterator<<Self::Item as TryFuture>::Ok>,
1378 E: From<<Self::Item as TryFuture>::Error>,
1379 {
1380 futures::future::try_join_all(self)
1381 .await?
1382 .into_iter()
1383 .collect::<T>()
1384 .ok()
1385 }
1386
1387 #[cfg(feature = "async")]
1388 async fn try_wait<T, E: 'static + Send + Sync>(self) -> Result<T, AnyhowError>
1389 where
1390 Self: Is<JoinHandle<Result<T, E>>>,
1391 AnyhowError: From<E>,
1392 {
1393 self.into_self().await??.ok()
1394 }
1395
1396 #[must_use]
1397 fn type_name() -> &'static str {
1398 std::any::type_name::<Self>()
1399 }
1400
1401 fn unit(&self) {}
1402
1403 async fn wait_then_unwrap_or_pending<T>(self) -> T
1404 where
1405 Self: Future<Output = Option<T>> + Sized,
1406 {
1407 match self.await {
1408 Some(value) => value,
1409 None => std::future::pending().await,
1410 }
1411 }
1412
1413 async fn unwrap_or_pending_then_wait<F: Future + Unpin>(&mut self) -> F::Output
1414 where
1415 Self: BorrowMut<Option<F>>,
1416 {
1417 if let Some(future) = self.borrow_mut().as_mut() {
1418 future.await
1419 } else {
1420 std::future::pending().await
1421 }
1422 }
1423
1424 fn with<T>(&self, value: T) -> T {
1425 value
1426 }
1427
1428 fn with_item_pushed<T>(self, item: T) -> Vec<T>
1429 where
1430 Self: Is<Vec<T>>,
1431 {
1432 let mut vec = self.into_self();
1433
1434 vec.push(item);
1435
1436 vec
1437 }
1438
1439 fn with_str_pushed(self, rhs: &str) -> String
1440 where
1441 Self: Is<String>,
1442 {
1443 let mut string = self.into_self();
1444
1445 string.push_str(rhs);
1446
1447 string
1448 }
1449
1450 #[cfg(feature = "serde")]
1451 fn write_as_json_to<T: Write>(&self, writer: T) -> Result<(), SerdeJsonError>
1452 where
1453 Self: Serialize,
1454 {
1455 serde_json::to_writer(writer, self)
1456 }
1457
1458 fn write_all_and_flush<T: AsRef<[u8]>>(&mut self, byte_str: T) -> Result<(), IoError>
1459 where
1460 Self: Write + Unpin,
1461 {
1462 self.write_all(byte_str.as_ref())?;
1463
1464 self.flush()
1465 }
1466
1467 #[cfg(feature = "async")]
1468 async fn write_all_and_flush_async<T: AsRef<[u8]>>(&mut self, byte_str: T) -> Result<(), IoError>
1469 where
1470 Self: AsyncWriteExt + Unpin,
1471 {
1472 self.write_all(byte_str.as_ref()).await?;
1473
1474 self.flush().await
1475 }
1476}
1477
1478impl<T: ?Sized> Utils for T {}