imago/
misc_helpers.rs

1//! Miscellaneous helper functions.
2
3use std::io;
4use std::ops::Range;
5
6/// Checks whether something overlaps with something else.
7pub(crate) trait Overlaps {
8    /// Does this overlap with `other`?
9    fn overlaps(&self, other: &Self) -> bool;
10}
11
12impl<I: Ord> Overlaps for Range<I> {
13    fn overlaps(&self, other: &Self) -> bool {
14        self.start < other.end && other.start < self.end
15    }
16}
17
18/// Prepend `Error` messages by context.
19///
20/// Trait for `Error` objects that allows prepending their error messages by something that gives
21/// context.
22pub(crate) trait ErrorContext {
23    /// Prepend the error by `context`.
24    fn context<C: std::fmt::Display>(self, context: C) -> Self;
25}
26
27impl ErrorContext for io::Error {
28    fn context<C: std::fmt::Display>(self, context: C) -> Self {
29        io::Error::new(self.kind(), format!("{context}: {self}"))
30    }
31}
32
33/// Give results context in case of error.
34///
35/// Lifts the `ErrorContext` trait to `Result` types.
36pub(crate) trait ResultErrorContext {
37    /// Give context if `self` is an error.
38    ///
39    /// If `self` is an error, prepend the given `context`.
40    fn err_context<C: std::fmt::Display, F: FnOnce() -> C>(self, context: F) -> Self;
41}
42
43impl<V, E: ErrorContext> ResultErrorContext for Result<V, E> {
44    fn err_context<C: std::fmt::Display, F: FnOnce() -> C>(self, context: F) -> Self {
45        self.map_err(|err| err.context(context()))
46    }
47}
48
49/// Similar to `AsRef`, but for types where `AsRef` is not implemented.
50///
51/// When we need `AsRef` for a type but it is not implemented in its origin crate, there is no way
52/// but to provide a local trait that we can implement here.  Because there are no negative trait
53/// bounds, we cannot implement this for `AsRef` (to have a common trait).
54///
55/// Also includes a lifetime so that it is possible to borrow things for longer.
56#[cfg(feature = "vm-memory")]
57pub trait ImagoAsRef<'a, T: ?Sized> {
58    /// Return a simple reference for `self`.
59    fn as_ref(&self) -> &'a T;
60}
61
62#[cfg(feature = "vm-memory")]
63impl<'a, T: ?Sized, U: ImagoAsRef<'a, T>> ImagoAsRef<'a, T> for &'a U {
64    fn as_ref(&self) -> &'a T {
65        <U as ImagoAsRef<T>>::as_ref(self)
66    }
67}
68
69#[cfg(feature = "vm-memory")]
70impl<'a, B: vm_memory::bitmap::BitmapSlice> ImagoAsRef<'a, vm_memory::VolatileSlice<'a, B>>
71    for &'a vm_memory::VolatileSlice<'a, B>
72{
73    fn as_ref(&self) -> &'a vm_memory::VolatileSlice<'a, B> {
74        self
75    }
76}
77
78/// Repeat a syscall while it returns `EINTR`.
79///
80/// Invoke the given syscall, check whether it returned an error (i.e. the integer value -1), and
81/// if so, turn it into an `io::Error`.  If that error is `EINTR`, re-run the syscall, multiple
82/// times if necessary.
83///
84/// If no error was returned (i.e. not -1), return the returned value.
85#[cfg(unix)]
86pub(crate) fn while_eintr<R: From<i8> + PartialEq, F: FnMut() -> R>(
87    mut syscall: F,
88) -> io::Result<R> {
89    loop {
90        let ret: R = syscall();
91        if ret == R::from(-1i8) {
92            let err = io::Error::last_os_error();
93            if err.raw_os_error() != Some(libc::EINTR) {
94                return Err(err);
95            }
96        } else {
97            return Ok(ret);
98        }
99    }
100}
101
102/// Generate an `io::Error` of kind `InvalidData`.
103pub(crate) fn invalid_data<E: Into<Box<dyn std::error::Error + Send + Sync>>>(
104    error: E,
105) -> io::Error {
106    io::Error::new(io::ErrorKind::InvalidData, error)
107}