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
//! # Multireferences (aka _the inverse distributive law_) //! //! Ever wanted to get `&[T]` from `[&T]` without cloning anything? //! //! Semantically, it doesn't make sense (because a slice wraps a block of //! _contiguous_ elements). But sometimes it's very convenient to be //! able to “algebraically” extract a common lifetime //! from a bunch of references. //! //! This crate provides two helper types //! [`Slice`](struct.Slice.html) and [`Pair`](struct.Pair.html) //! that allow the following conversions: //! //! * [`&'a [&'x T] -> &'a Slice<T>`](struct.Slice.html#method.new) (and a mutable equivalent) //! * [`&'a (&'x A, &'x B) -> &'a Pair<A, B>`](struct.Pair.html#method.new) (and a mutable equivalent) //! //! Moreover, each of these types provides `.as_ref()` and `.as_mut()` //! methods (with signatures different from the ones used by the `AsRef` and //! `AsMut` traits) implementing the forward distributive law: //! //! * [`&'a Slice<T> -> &'a [&'a T]`](struct.Slice.html#method.as_ref) (and a mutable equivalent) //! * [`&'a Pair<A, B> -> &'a (&'a A, &'a B)`](struct.Pair.html#method.as_ref) (and a mutable equivalent) //! // //! Also there is a macro `declare_named_tuple!` that introduces // //! a user-defined helper type which allows to name // //! the individual wrapped references. //! //! ## Motivation //! //! _The following text is somewhat long. Unfortunately, I do not //! know any realistic uses of the inverse distributive law in situations //! not involving a formal argument in a contra-contravariant position._ //! //! ### Preliminaries //! //! Suppose you have the following trait: //! //! ``` //! trait Info { //! type RelevantPart: ?Sized; //! //! fn info<E, Info>(&self, extractor: E) -> Info where //! E: FnOnce(&Self::RelevantPart) -> Info; //! } //! ``` //! //! I.e. a type implementing `Info` can temporarily give access to //! some its part. For example: //! //! ``` //! # trait Info { type RelevantPart: ?Sized; //! # fn info<E, Info>(&self, extractor: E) -> Info where //! # E: FnOnce(&Self::RelevantPart) -> Info; } //! # use std::collections::HashMap; //! struct Configuration { //! fields: HashMap<String, String>, //! } //! //! impl Info for Configuration { //! type RelevantPart = str; //! //! fn info<E, Info>(&self, extractor: E) -> Info where //! E: FnOnce(&str) -> Info //! { //! match self.fields.get("name") { //! Some(name) => extractor(name), //! None => extractor("UNKNOWN"), //! } //! } //! } //! ``` //! //! If you are interested whether the continuation-passing style is necessary, //! try to write a non-cps equivalent //! //! ``` //! # struct Foo; impl Foo { //! fn info<'a>(&'a self) -> &'a str //! # { todo!() } } //! ``` //! //! for some dynamically generated string (e.g. the current timestamp) instead //! of static `"UNKNOWN"`. //! //! The only safe way to get the `&'a str` from such a string seems to be //! to embed this string directly in the `Configuration`. But it can't be done //! through a shared reference (and if it could, it would be a rather //! strange-looking solution, because this string has nothing to do with //! the configuration). //! //! ### The problem //! //! Now suppose that you want to give two fields to the extractor. //! What the `RelevantPart` would be? //! //! The laziest solution is to define //! //! ``` //! type RelevantPart = (String, String); //! ``` //! //! But such a type requires cloning the strings. It would be better to have //! //! ``` //! # trait Foo { type RelevantPart; } impl<'a> Foo for &'a () { //! type RelevantPart = (&'a str, &'a str); //! # } //! ``` //! //! but our trait doesn't have the `'a` parameter. And if it had it //! would not work either. E.g. a `&str` borrowed from a dynamically //! generated analogue of `"UNKNOWN"` must have its lifetime fully //! contained in the `info` method. But the `'a` lifetime is external //! to this method. //! //! ### A solution //! //! ``` //! # trait Info { type RelevantPart: ?Sized; //! # fn info<E, Info>(&self, extractor: E) -> Info where //! # E: FnOnce(&Self::RelevantPart) -> Info; } //! # use std::collections::HashMap; //! # struct Configuration { fields: HashMap<String, String> } //! fn make_error_string() -> String { unimplemented!() } //! //! use multiref::Pair; // a wrapper around (&'a A, &'a B) //! //! impl Info for Configuration { //! type RelevantPart = Pair<str, str>; // now this type supports any lifetime //! //! fn info<E, Info>(&self, extractor: E) -> Info where //! E: FnOnce(&Pair<str,str>) -> Info //! { //! let error_string = make_error_string(); //! // for simplicity we generate an error string unconditionally //! //! let foo: &str = match self.fields.get("foo") { //! Some(foo) => &foo, //! None => &error_string, //! }; //! //! let bar: &str = match self.fields.get("bar") { //! Some(bar) => &bar, //! None => &error_string, //! }; //! //! extractor( (&(foo, bar)).into() ) //! // Pair::new(&(foo, bar)) also can be used //! } //! } //! ``` //! //! //! ## Warning //! //! This crate uses some `unsafe` code with questionable soundness. It seems //! that this code is sound if DST are sound, but it may not be the case. #![no_std] mod slice; mod pair; mod named_tuple; pub use pair::Pair; pub use slice::Slice;