polonius_the_crab/lib.rs
1#![doc = include_str!("../README.md")]
2#![no_std]
3#![cfg_attr(feature = "polonius",
4 forbid(unsafe_code),
5)]
6#![allow(uncommon_codepoints)]
7
8/// ACT I SCENE I. Elsinore. A platform before the castle.
9pub
10mod prelude {
11 pub use crate::{
12 exit_polonius,
13 polonius,
14 polonius_break,
15 polonius_break_dependent,
16 polonius_continue,
17 polonius_loop,
18 polonius_return,
19 polonius_try,
20 };
21}
22
23#[doc(no_inline)]
24pub use ::higher_kinded_types::ForLt;
25
26pub use macros::ඞ;
27mod macros;
28
29mod r#try;
30
31/// The key stone of the API of this crate.
32/// See the [top-level docs][crate] for more info.
33///
34/// Signature formatted for readability:
35/**
36```rust
37# const _IGNORED: &str = stringify! {
38fn polonius<'i, Input : ?Sized, OwnedOutput, BorrowingOutput : ?Sized> (
39 input_borrow: &'i mut Input,
40 branch:
41 impl for<'any>
42 FnOnce(&'any mut Input)
43 -> PoloniusResult<
44 BorrowingOutput::Of<'any>,
45 OwnedOutput, // -----------+
46 > // |
47 , // | `polonius()`
48) -> PoloniusResult< // | magic
49 BorrowingOutput::Of<'i>, // | adds "back"
50 OwnedOutput, &'i mut Input, // <-------+ the `input_borrow`
51 >
52where
53 BorrowingOutput : ForLt,
54# };
55``` */
56///
57/// ## Turbofishing a `ForLt!()` parameter.
58///
59/// As described in the [top-level docs][crate], the key aspect that allows this
60/// function to be both _sound_, and _generic_, is that it involves a
61/// `for<'any>`-quantified lifetime in its [branching][PoloniusResult] closure,
62/// and a lifetime-generic generic type parameter.
63///
64/// There was no stutter: this is indeed a generic generic type parameter: the
65/// API is said to be "higher-kinded", related to HKTs ([higher-kinded
66/// types][hkts]).
67///
68/// Hence the <code>BorrowingOutput : [ForLt]</code> (lifetime-generic) generic
69/// type parameter.
70///
71/// [ForLt]: trait@ForLt
72///
73/// Such "`For` types" involved in these HKT APIs, however, **cannot be
74/// elided**, since they do not play well with **type inference**.
75///
76/// This means that turbofishing this _third_ type parameter is:
77/// - mandatory;
78/// - to be done using the [`ForLt!`] macro.
79///
80/// ```rust
81/// # /*
82/// polonius::<_, _, ForLt!(…)>(…)
83/// # */
84/// ```
85///
86/// [hkts]: https://docs.rs/higher-kinded-types
87///
88/// If this sounds too complex or abstract, know that there also are:
89///
90/// ## Easier APIs for the most pervasive use cases
91///
92/// These are provided as the macros that accompany this crate:
93///
94/// - [`polonius!`] for most cases;
95///
96/// - [`polonius_loop!`] as extra sugar for a specific shape of
97/// `loop { polonius!(…) }`
98///
99/// - ⚠️ [not every `loop { polonius!(…); … }` case can be translated][l]
100/// to a `polonius_loop!`. When in doubt, fall back to a lower-level
101/// [`polonius!`] invocation, or even to a manual [`polonius()`] call.
102///
103/// [l]: https://github.com/danielhenrymantilla/polonius-the-crab.rs/issues/11
104pub
105fn polonius<'i, Input : ?Sized, OwnedOutput, BorrowingOutput : ?Sized> (
106 input_borrow: &'i mut Input,
107 branch:
108 impl for<'any>
109 FnOnce(&'any mut Input)
110 -> PoloniusResult<
111 BorrowingOutput::Of<'any>,
112 OwnedOutput,
113 >
114 ,
115) -> PoloniusResult<
116 BorrowingOutput::Of<'i>,
117 OwnedOutput, &'i mut Input,
118 >
119where
120 BorrowingOutput : ForLt,
121{
122 #[cfg(feature = "polonius")]
123 let tentative_borrow = &mut *input_borrow;
124 #[cfg(not(feature = "polonius"))]
125 let tentative_borrow = unsafe {
126 // SAFETY:
127 // > Though this be `unsafe`, there is soundness in 't.
128 //
129 // More seriously, read the docs, I've detailed the reasoning there
130 // in great length. And/or check the `tests/soundness.rs` test,
131 // which `cargo check`s this very snippet without this `unsafe`.
132 &mut *(input_borrow as *mut _)
133 };
134 let owned_value = match branch(tentative_borrow) {
135 | PoloniusResult::Borrowing(dependent) => {
136 return PoloniusResult::Borrowing(dependent);
137 },
138 | PoloniusResult::Owned { value, .. } => value,
139 }; // <- `drop(PoloniusResult::Owned { .. })`.
140 // See https://github.com/rust-lang/rust/issues/126520 for more info.
141 PoloniusResult::Owned {
142 value: owned_value,
143 input_borrow,
144 }
145}
146
147/// Placeholder type to be used when _constructing_ a
148/// [`PoloniusResult::Owned`].
149///
150/// [`PoloniusResult::Owned`]: type@PoloniusResult::Owned
151///
152/// Since there is no access to the original `input_borrow` yet (due to the
153/// very polonius limitation that makes this crate necessary), this
154/// [`Placeholder`] is used in its stead.
155///
156/// ```rust, no_run
157/// use ::polonius_the_crab::*;
158///
159/// type StringRef = ForLt!(&str);
160///
161/// let map: &mut ::std::collections::HashMap<i32, String> = // ...
162/// # None.unwrap();
163///
164/// # use drop as stuff;
165/// #
166/// match polonius::<_, _, StringRef>(map, |map| match map.get(&22) {
167/// | Some(ret) => PoloniusResult::Borrowing(ret),
168/// | None => PoloniusResult::Owned {
169/// value: 42,
170/// input_borrow: /* WHAT TO PUT HERE?? */ Placeholder, // 👈👈
171/// },
172/// }) {
173/// // `polonius` magic
174/// | PoloniusResult::Borrowing(dependent_entry) => {
175/// // ...
176/// stuff(dependent_entry);
177/// },
178/// | PoloniusResult::Owned {
179/// value,
180/// input_borrow: map, // we got our `map` borrow back! 🙌
181/// } => {
182/// assert_eq!(value, 42);
183/// stuff(map);
184/// },
185/// }
186/// ```
187///
188/// Note that despite intellectually interesting w.r.t properly understanding
189/// the API, providing that `input_borrow: Placeholder` does not provide any
190/// valuable information to the call, and is thus rather noisy.
191///
192/// Hence the [`PoloniusResult::Owned()`] constructor shorthand,
193/// so as to be able to write:
194///
195/// ```rust
196/// # const _IGNORED: &str = stringify! {
197/// PoloniusResult::Owned(42)
198/// // is just a shorthand for:
199/// PoloniusResult::Owned {
200/// value: 42,
201/// input_borrow: /* WHAT TO PUT HERE?? */ Placeholder, // 👈👈
202/// }
203/// # };
204/// ```
205pub
206struct Placeholder;
207
208/// Output type of both the [`polonius()`] function and the closure it takes.
209///
210/// It represents the conceptual code-flow / branch disjunction between:
211///
212/// - having some _dependent_ type still [`Borrowing`][Self::Borrowing] from
213/// the `input_borrow` _given_/forfeited to [`polonius()`];
214///
215/// - or having no such type, _i.e._, having only "[`Owned`][type@Self::Owned]"
216/// (as far as the `input_borrow` is concerned) output.
217///
218/// - [`polonius()`] magic makes it so, in this branch/case, its
219/// `.input_borrow` shall be populated for the caller to get back access
220/// to it.
221pub
222enum PoloniusResult<BorrowingOutput, OwnedOutput, InputBorrow = Placeholder> {
223 /// Variant to return in the "happy" case where our tentative (re)borrow
224 /// actually yielded some dependent / still-`Borrowing` type which we wish
225 /// to keep hold of, _e.g._, [to `return` it from the
226 /// function][`polonius_return!`].
227 Borrowing(BorrowingOutput),
228
229 /// Variant to return in the branches where we are done with any dependent
230 /// value, and we would like to instead get our `input_borrow` back.
231 Owned {
232 /// The inner `value` of the [`Self::Owned(value)`][Self::Owned()] case.
233 value: OwnedOutput,
234
235 /// When constructing this variant, inside [`polonius()`]' closure,
236 /// a [`Placeholder`] is to be put in its stead, to let [`polonius()`]
237 /// replace it with its `input_borrow`.
238 input_borrow: InputBorrow,
239 },
240}
241
242impl<BorrowingOutput, OwnedOutput> PoloniusResult<BorrowingOutput, OwnedOutput> {
243 /// Tuple-variant-looking sugar to _construct_
244 /// the <code>[Self::Owned]</code> variant.
245 ///
246 /// It's just convenience sugar for
247 /// <code>[Self::Owned] { value, input_borrow: [Placeholder] }</code>.
248 ///
249 /// ```rust
250 /// # const _IGNORED: &str = stringify! {
251 /// PoloniusResult::Owned(42)
252 /// // is the same as:
253 /// PoloniusResult::Owned {
254 /// value: 42,
255 /// input_borrow: Placeholder,
256 /// }
257 /// # };
258 /// ```
259 ///
260 /// See [`Placeholder`] for more info.
261 ///
262 /// [Self::Owned]: type@Self::Owned
263 #[allow(nonstandard_style)]
264 pub
265 const
266 fn Owned(value: OwnedOutput)
267 -> Self
268 {
269 Self::Owned {
270 value: value,
271 input_borrow: Placeholder,
272 }
273 }
274}
275
276#[cfg_attr(feature = "ui-tests",
277 cfg_attr(all(), doc = include_str!("compile_fail_tests.md")),
278)]
279mod _compile_fail_tests {}