1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::borrow::Cow;
use std::ffi::CStr;
use std::ffi::CString;
use std::ffi::OsStr;
use std::ffi::OsString;
use std::io::IoSlice;
use std::io::IoSliceMut;
use std::ops::Deref;
use std::path::Path;
use std::path::PathBuf;

#[derive(Debug)]
pub(super) enum BytesInner<'a> {
    Bytes(&'a [u8]),
    OsStr(&'a OsStr),
}

/// A value that can be printed by any of the functions in this crate.
///
/// For more information, see [`ToBytes`].
#[derive(Debug)]
pub struct Bytes<'a>(pub(super) BytesInner<'a>);

/// Represents a type similarly to [`Display`].
///
/// Implement this trait to allow printing a type that cannot guarantee UTF-8
/// output. It is used to bound values accepted by functions in this crate.
///
/// Since [`Bytes`] has no public constructor, implementations should call
/// [`to_bytes`] on another type to create an instance.
///
/// ### Note: Future Compatibility
///
/// This trait should not be implemented for types that also implement
/// [`Display`] or [`ToString`]. A blanket implementation may eventually be
/// provided to cover those traits automatically, but that would currently be
/// considered a coherence violation.
///
/// # Examples
///
/// ```
/// use print_bytes::println_bytes;
/// use print_bytes::Bytes;
/// use print_bytes::ToBytes;
///
/// struct ByteSlice<'a>(&'a [u8]);
///
/// impl ToBytes for ByteSlice<'_> {
///     fn to_bytes(&self) -> Bytes<'_> {
///         self.0.to_bytes()
///     }
/// }
///
/// println_bytes(&ByteSlice(b"Hello, world!"));
/// ```
///
/// [`Display`]: ::std::fmt::Display
/// [`to_bytes`]: Self::to_bytes
/// [`ToString`]: ::std::string::ToString
pub trait ToBytes {
    /// Creates a byte sequence that will be used to represent the instance.
    #[must_use]
    fn to_bytes(&self) -> Bytes<'_>;
}

impl ToBytes for [u8] {
    #[inline]
    fn to_bytes(&self) -> Bytes<'_> {
        Bytes(BytesInner::Bytes(self))
    }
}

#[cfg_attr(print_bytes_docs_rs, doc(cfg(feature = "min_const_generics")))]
#[cfg(any(feature = "const_generics", feature = "min_const_generics"))]
impl<const N: usize> ToBytes for [u8; N] {
    #[inline]
    fn to_bytes(&self) -> Bytes<'_> {
        self[..].to_bytes()
    }
}

impl<T> ToBytes for Cow<'_, T>
where
    T: ?Sized + ToBytes + ToOwned,
    T::Owned: ToBytes,
{
    #[inline]
    fn to_bytes(&self) -> Bytes<'_> {
        (**self).to_bytes()
    }
}

impl ToBytes for OsStr {
    #[inline]
    fn to_bytes(&self) -> Bytes<'_> {
        Bytes(BytesInner::OsStr(self))
    }
}

macro_rules! r#impl {
    ( $type:ty , $convert_method:ident ) => {
        impl ToBytes for $type {
            #[inline]
            fn to_bytes(&self) -> Bytes<'_> {
                ToBytes::to_bytes(self.$convert_method())
            }
        }
    };
}
r#impl!(CStr, to_bytes);
r#impl!(CString, as_c_str);
r#impl!(IoSlice<'_>, deref);
r#impl!(IoSliceMut<'_>, deref);
r#impl!(OsString, as_os_str);
r#impl!(Path, as_os_str);
r#impl!(PathBuf, as_path);
r#impl!(Vec::<u8>, as_slice);