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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#![no_std]

//! Marker types to indicate precisely the [variance] relationship between a
//! generic type and its parameters.
//!
//! Rust supports three different modes of variance between a generic type `F`
//! and a type parameter `T`:<sup>[1]</sup>
//!  - Covariance: `F<T>` is a subtype of `F<U>` if `T` is a subtype of `U`.
//!  - Contravariance: `F<T>` is a subtype of `F<U>` if `U` is a subtype of `T`.
//!  - Invariance: `F<T>` is never a subtype of `F<U>` (unless `T = U`).
//!
//! Rust is usually able to infer the variance of a type parameter from its use,
//! but fails if the type parameter is not used within the type definition.
//! Typically, this is resolved by using a [`PhantomData`] to indicate the
//! parameter's use within the type:
//! ```
//! use std::marker::PhantomData;
//!
//! struct Slice<'a, T: 'a> {
//!     start: *const T,
//!     end: *const T,
//!     phantom: PhantomData<&'a T>,
//! }
//! ```
//!
//! However, in some cases, the subtyping relation is not always obvious from a
//! `PhantomData` field. In such cases, it can be useful to make the variance
//! explicit with one of the markers [`Covariant`], [`Contravariant`], and
//! [`Invariant`].
//! ```
//! use type_variance::{Covariant, Contravariant};
//!
//! struct Func<Arg, Ret> {
//!     arg: Covariant<Arg>,
//!     ret: Contravariant<Ret>,
//! }
//! ```
//!
//! ## Enforcing invariance
//!
//! Another use case is when a type parameter is used, but the Rust compiler
//! deduces a more permissive variance than is desired. In this case, the
//! `Invariant` marker can be used to ensure that the generic type is invariant
//! with respect to the given type parameter.
//! ```
//! use type_variance::Invariant;
//!
//! struct Opaque<T> {
//!     inner: Box<T>,        // Implies `Opaque` is covariant to `T`
//!     marker: Invariant<T>, // Ensures that `Opaque` is invariant to `T`
//! }
//! ```
//! The `Invariant` overrules any other implied variances and so `Opaque`
//! becomes invariant to `T`.
//!
//! ## Lifetime parameters
//!
//! Like `PhantomData`, the provided variance markers only accept type
//! parameters. To indicate a generic type's variance with respect to its
//! lifetime parameters, use the [`Lifetime`] wrapper, which converts a
//! lifetime to a regular type while preserving its subtyping relation.
//!
//! # Limitations
//!
//! The marker traits `Covariant` and `Contravariant` _do not_ necessarily
//! guarantee that the compiler will use the marked variance. If two uses of a
//! type parameter imply differing variances, the compiler will consider the
//! generic type _invariant_ with respect to the parameter.
//!
//! For example:
//! ```
//! # use type_variance::Contravariant;
//! #
//! struct Ref<'a, T> {
//!     inner: &'a T,             // Implies `Ref` is covariant to `T`
//!     marker: Contravariant<T>, // Implies `Ref` is contravariant to `T`
//! }
//! ```
//! As a result of these conflicting variances, the compiler will decide that
//! `Ref` is invariant to `T`.
//!
//! Due to this, it is recommended that `Covariant` and `Contravariant` are only
//! used on type parameters that are not used in any other fields of the type.
//!
//! [variance]: https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)
//! [1]: https://doc.rust-lang.org/nomicon/subtyping.html#variance
//! [`PhantomData`]: https://doc.rust-lang.org/stable/std/marker/struct.PhantomData.html
//! [`Covariant`]: struct.Covariant.html
//! [`Contravariant`]: struct.Contravariant.html
//! [`Invariant`]: struct.Invariant.html
//! [`Lifetime`]: struct.Lifetime.html

use core::marker::PhantomData;

/// A sealed trait implemented by `Covariant<T>`, `Contravariant<T>`, and
/// `Invariant<T>`.
pub trait Variance: Default + private::Sealed {}

/// Zero-sized type used to mark a type as [covariant] with respect to its type
/// parameter `T`.
///
/// [covariant]: https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)
///
/// See the [module-level documentation](index.html) for more.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Covariant<T: ?Sized> {
    marker: PhantomData<fn() -> T>,
}

/// Zero-sized type used to mark a type as [contravariant] with respect to its type
/// parameter `T`.
///
/// [contravariant]: https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)
///
/// See the [module-level documentation](index.html) for more.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Contravariant<T: ?Sized> {
    marker: PhantomData<fn(T)>,
}

/// Zero-sized type used to mark a type as [invariant] with respect to its type
/// parameter `T`.
///
/// [invariant]: https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)
///
/// See the [module-level documentation](index.html) for more.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Invariant<T: ?Sized> {
    marker: (Covariant<T>, Contravariant<T>),
}

// NOTE: These manual impls are necessary due to the following issue, but
// can be replaced with a #[derive(Default)] when/if it gets resolved.
// https://github.com/rust-lang/rust/issues/26925
impl<T: ?Sized> Default for Covariant<T> {
    fn default() -> Self {
        Self { marker: Default::default(), }
    }
}
impl<T: ?Sized> Default for Contravariant<T> {
    fn default() -> Self {
        Self { marker: Default::default(), }
    }
}
impl<T: ?Sized> Default for Invariant<T> {
    fn default() -> Self {
        Self { marker: Default::default(), }
    }
}

impl<T: ?Sized> private::Sealed for Covariant<T> {}
impl<T: ?Sized> private::Sealed for Contravariant<T> {}
impl<T: ?Sized> private::Sealed for Invariant<T> {}

impl<T: ?Sized> Variance for Covariant<T> {}
impl<T: ?Sized> Variance for Contravariant<T> {}
impl<T: ?Sized> Variance for Invariant<T> {}

/// Variance-preserving type wrapper around a lifetime parameter.
///
/// This can be useful to indicate the variance of a generic type with respect
/// to a lifetime parameter, rather than a type parameter.
///
/// For example:
/// ```
/// use type_variance::{Covariant, Lifetime};
///
/// struct Guard<'a> {
///     marker: Covariant<Lifetime<'a>>,
/// }
/// ```
/// This marks `Guard` as being covariant to `'a`.
///
/// Note that this type is not constructible, and so should be wrapped with
/// either a `PhantomData` or one of the variance marker types.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Lifetime<'a> {
    _variance: Covariant<&'a ()>,
}

/// A convenience function for constructing any of `Covariant<T>`,
/// `Contravariant<T>`, and `Invariant<T>`. It is equivalent to [`default`].
///
/// [`default`]: https://doc.rust-lang.org/stable/std/default/trait.Default.html#tymethod.default
///
/// For example:
/// ```
/// use type_variance::{Covariant, variance};
///
/// struct Co<T> {
///     other_data: u32,
///     marker: Covariant<T>,
/// }
///
/// impl<T> Co<T> {
///     fn new() -> Self {
///         Co {
///             other_data: 42,
///             marker: variance(),
///         }
///     }
/// }
/// ```
pub fn variance<T: Variance>() -> T {
    Default::default()
}

// Prevent external implementations of `Variance`.
mod private {
    pub trait Sealed {}
}

#[cfg(test)]
mod tests {
    use super::{Covariant, Contravariant, Lifetime};

    struct Co<X>(Covariant<X>);
    struct Contra<X>(Contravariant<X>);

    #[test]
    fn covariant<'a>() {
        let _co: Co<Lifetime<'a>> = Co(
            Covariant::<Lifetime<'static>>::default(),
        );
    }

    #[test]
    fn contravariant<'a>() {
        let _contra: Contra<Lifetime<'static>> = Contra(
            Contravariant::<Lifetime<'a>>::default(),
        );
    }

    #[test]
    fn co_contra<'a>() {
        struct Func<Arg, Ret> {
            _arg: Covariant<Arg>,
            _ret: Contravariant<Ret>,
        }
        let _func: Func<Lifetime<'a>, Lifetime<'static>> = Func {
            _arg: Covariant::<Lifetime<'static>>::default(),
            _ret: Contravariant::<Lifetime<'a>>::default(),
        };
    }
}