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 {}