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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! # trapper
//!
//! Trapper (or transparent wrapper) allows for the creation of transparent type wrappers,
//! that is types which are transparent and can be wrapped and unwrapped for zero cost.

extern crate self as trapper;

/// A type wrapper. This trait provides methods for converting between a wrapper and its
/// inner type. It should only be implemented by types through the `newtype` macro. If it must
/// be implemented manually, the type should have transparent representation to be safe.
pub unsafe trait Wrapper: Sized {
    /// The inner wrapped type
    type Inner: Sized;

    /// Wraps the value, returning a new instance of the wrapper.
    ///
    /// # Example
    ///
    /// ```
    /// use trapper::{Wrapper, newtype};
    /// newtype!(#[derive(PartialEq, Debug)] type NumberWrapper(i32));
    ///
    /// # fn main() {
    /// let wrapper = NumberWrapper::wrap(12);
    /// let other = NumberWrapper::wrap(12);
    /// assert_eq!(wrapper, other);
    /// # }
    /// ```
    fn wrap(inner: Self::Inner) -> Self;
    /// Unwraps the wrapper, returning its inner value.
    ///
    /// # Example
    ///
    /// ```
    /// use trapper::{Wrapper, newtype};
    /// newtype!(type NumberWrapper(i32));
    ///
    /// # fn main() {
    /// let wrapper = NumberWrapper::wrap(12);
    /// assert_eq!(wrapper.unwrap(), 12);
    /// # }
    /// ```
    fn unwrap(self) -> Self::Inner;

    /// Wraps a shared reference to the value in the wrapper type
    ///
    /// # Example
    ///
    /// ```
    /// use trapper::{Wrapper, newtype};
    /// newtype!(type NumberWrapper(i32));
    ///
    /// # fn main() {
    /// let number = 12;
    /// let wrapper: &NumberWrapper = NumberWrapper::wrap_ref(&number);
    /// # }
    /// ```
    fn wrap_ref(inner: &Self::Inner) -> &Self {
        unsafe { &*(inner as *const Self::Inner as *const Self) }
    }
    /// Wraps a unique reference to the value in the wrapper type
    ///
    /// # Example
    ///
    /// ```
    /// use trapper::{Wrapper, newtype};
    /// newtype!(type NumberWrapper(i32));
    ///
    /// # fn main() {
    /// let mut number = 12;
    /// let wrapper: &mut NumberWrapper = NumberWrapper::wrap_mut(&mut number);
    /// *wrapper = NumberWrapper::wrap(13);
    ///
    /// assert_eq!(number, 13);
    /// # }
    /// ```
    fn wrap_mut(inner: &mut Self::Inner) -> &mut Self {
        unsafe { &mut *(inner as *mut Self::Inner as *mut Self) }
    }

    /// Unwraps a shared reference to the wrapper, exposing the underlying type
    ///
    /// # Example
    ///
    /// ```
    /// use trapper::{Wrapper, newtype};
    /// newtype!(type NumberWrapper(i32));
    ///
    /// # fn main() {
    /// let wrapper = NumberWrapper::wrap(12);
    ///
    /// assert_eq!(*wrapper.unwrap_ref(), 12);
    /// # }
    /// ```
    fn unwrap_ref(&self) -> &Self::Inner {
        unsafe { &*(self as *const Self as *const Self::Inner) }
    }
    /// Unwraps a unique reference to the wrapper, exposing the underlying type
    ///
    /// # Example
    ///
    /// ```
    /// use trapper::{Wrapper, newtype};
    /// newtype!(#[derive(PartialEq, Debug)] type NumberWrapper(i32));
    ///
    /// # fn main() {
    /// let mut wrapper = NumberWrapper::wrap(12);
    /// *wrapper.unwrap_mut() = 13;
    ///
    /// assert_eq!(wrapper, NumberWrapper::wrap(13));
    /// # }
    /// ```
    fn unwrap_mut(&mut self) -> &mut Self::Inner {
        unsafe { &mut *(self as *mut Self as *mut Self::Inner) }
    }
}

pub use trapper_macro::newtype;

#[cfg(test)]
mod tests {
    use super::newtype;

    newtype!(#[allow(dead_code)] type InMod(i32));
    newtype!(#[allow(dead_code)] type WithLifetimes<'a>(std::io::StderrLock<'a>));
    newtype!(#[allow(dead_code)] type WithTypeParameters<T>(T));
    newtype!(#[allow(dead_code)] type WithBoth<'a, T>(&'a T));
    newtype!(#[allow(dead_code)] type WithClause<'a, T>(&'a T) where T: Default);
    newtype! {
        #[allow(dead_code)]
        /// doc
        type AttributesDocsLifetimesTypesClausesTrailingSemicolon<'a, 'b, 'c, T>(&'a &'b &'c T) where T: Default + Clone, 'a: 'b;
    }
    newtype! {
        type NoWhereClause<'a: 'b, 'b, T = i32>(&'b &'a T);
    }
}