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
//! A crate for targeting and accessing _actual implementation_.
//!
//! Take an example trait:
//!
//! ```rust
//! # struct Website;
//! trait ScrapeTheInternet {
//! fn scrape_the_internet(&self) -> Vec<Website>;
//! }
//! ```
//!
//! The trait represents some abstract computation. The trait exports a method signature that
//! can be implemented by types. In this case, we can imagine what a true implementation of the
//! trait will do: _Actually scrape the internet_.
//!
//! `implementation` provides the [Impl] type as an implementation target for traits having the following semantics:
//!
//! * The trait has only one actual, true implementation.
//! * Other implementations of the trait _may exist_, but these are interpreted as _fake_, _mocked_ in some way.
//!
//! `implementation` enables a standardized way of writing these actual implementations in a way
//! that allows the actual `Self`-receiver type to be unknown.
//!
//! # Usage
//! To define the actual, generic implementation of `ScrapeTheInternet`, we can write the following impl:
//!
//! ```rust
//! # struct Website;
//! # trait ScrapeTheInternet {
//! # fn scrape_the_internet(&self) -> Vec<Website>;
//! # }
//! impl<T> ScrapeTheInternet for implementation::Impl<T> {
//! fn scrape_the_internet(&self) -> Vec<Website> {
//! todo!("find all the web pages, etc")
//! }
//! }
//! ```
//!
//! This code implements the trait for [Impl], and by doing that we have asserted
//! that it is the actual, true implementation.
//!
//! The implementation is fully generic, and works for any `T`.
//!
//! ```no_run
//! # struct Website;
//! # trait ScrapeTheInternet {
//! # fn scrape_the_internet(&self) -> Vec<Website>;
//! # }
//! # impl<T> ScrapeTheInternet for implementation::Impl<T> {
//! # fn scrape_the_internet(&self) -> Vec<Website> {
//! # todo!("find all the web pages, etc")
//! # }
//! # }
//! use implementation::Impl;
//!
//! struct MyType;
//!
//! let websites = Impl::new(MyType).scrape_the_internet();
//! ```
//!
//! ## Trait bounds
//! The advantage of keeping trait implementations generic, is that the self type might
//! live in a downstream crate. Let's say we need to access a configuration parameter
//! from `scrape_the_internet`. E.g. the maximum number of pages to scrape:
//!
//! ```rust
//! use implementation::Impl;
//!
//! # struct Website;
//! # trait ScrapeTheInternet {
//! # fn scrape_the_internet(&self) -> Vec<Website>;
//! # }
//! trait GetMaxNumberOfPages {
//! fn get_max_number_of_pages(&self) -> Option<usize>;
//! }
//!
//! impl<T> ScrapeTheInternet for Impl<T>
//! where Impl<T>: GetMaxNumberOfPages
//! {
//! fn scrape_the_internet(&self) -> Vec<Website> {
//! let max_number_of_pages = self.get_max_number_of_pages();
//! todo!("find all the web pages, etc")
//! }
//! }
//! ```
//!
//! Now, for this to work, `Impl<T>` also needs to implement `GetMaxNumberOfPages` (for the same `T` that is going to be used).
//!
//! `GetMaxNumberOfPages` would likely be implemented for a specific `T` rather than a generic one,
//! since that `T` would typically be some configuration holding that number:
//!
//! ```rust
//! # trait GetMaxNumberOfPages {
//! # fn get_max_number_of_pages(&self) -> Option<usize>;
//! # }
//! struct Config {
//! max_number_of_pages: Option<usize>
//! }
//!
//! impl GetMaxNumberOfPages for implementation::Impl<Config> {
//! fn get_max_number_of_pages(&self) -> Option<usize> {
//! self.max_number_of_pages
//! }
//! }
//! ```
//!
//! # Explanation
//!
//! This crate is the solution to a trait coherence problem.
//!
//! Given the trait above, we would like to provide an actual and a mocked implementation.
//! We might know what its actual implementation looks like as an algorithm, but
//! _not what type it should be implemented for_. There could be several reasons
//! to have a generic Self:
//!
//! * The `Self` type might live in a downstream crate
//! * It is actually designed to work generically
//!
//! If we had used a generic Self type (`impl<T> DoSomething for T`), the trait
//! would be unable to also have distinct fake implementations, because that would break
//! the coherence rules: A generic ("blanket") impl and a specialized
//! impl are not allowed to exist at the same time, because that would lead to ambiguity.
//!
//! To solve that, a concrete type is needed as implementation target. But that
//! type is allowed to be generic _internally_. It's just the root level that
//! needs to be a concretely named type.
//!
//! That type is the [Impl] type.
//!
//! When we use this implementation, we can create as many fake implementations as we want.
//!
/// Wrapper type for targeting and accessing actual implementation.
///
/// [Impl] has smart-pointer capabilities, as it implements [std::ops::Deref] and [std::ops::DerefMut].
/// You may freely choose what kind of `T` you want to wrap. It may be an owned one or it could be
/// a `&T`. Each have different tradeoffs.
///
/// An owned `T` is the most flexible in implementations, but that requires always owning "sub-implementations"
/// through an `Impl`:
///
/// ```rust
/// use implementation::Impl;
///
/// struct MyConfig {
/// param1: i32,
/// sub_config: Impl<SubConfig>,
/// }
///
/// struct SubConfig {
/// param2: i32,
/// }
/// ```
///
/// A referenced `&T` makes it possible to _borrow_ an `Impl` from any `T`, but that _could_ prove to be
/// more troublesome in some implementations. This also will require a reference-within-reference
/// design in trait methods with a `&self` receiver, and some more boilerplate if it needs to be cloned:
///
/// ```
/// use implementation::Impl;
///
/// trait DoSomething {
/// fn something(&self);
/// }
///
/// impl<'t, T> DoSomething for Impl<&'t T>
/// where T: Clone + Send + 'static
/// {
/// // self is an `&Impl<&T>`:
/// fn something(&self) {
///
/// // it will require some more code to make a proper clone of T:
/// let t_clone = self.into_inner().clone();
///
/// let handle = std::thread::spawn(move || {
/// let implementation = Impl::new(&t_clone);
///
/// // Do something else with Impl<&T>
/// });
///
/// handle.join().unwrap();
/// }
/// }
/// ```
#[derive(Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Impl<T>(T);
impl<T> Impl<T> {
/// Construct a new [Impl].
pub fn new(value: T) -> Impl<T> {
Impl(value)
}
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> From<T> for Impl<T> {
fn from(value: T) -> Impl<T> {
Impl(value)
}
}
impl<T> std::ops::Deref for Impl<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> std::ops::DerefMut for Impl<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> AsRef<T> for Impl<T> {
fn as_ref(&self) -> &T {
&self.0
}
}