polonius_the_crab/
macros.rs

1#[allow(unused)]
2use super::{
3    exit_polonius,
4    polonius,
5    polonius_break,
6    polonius_break_dependent,
7    polonius_continue,
8    polonius_loop,
9    polonius_return,
10    polonius_try,
11};
12
13/// Convenient entry-point to this crate's logic.
14///
15///   - See the [top-level docs][crate] for more info.
16///
17/// ## Usage
18///
19/**  - ```rust
20    use ::polonius_the_crab::prelude::*;
21
22    # fn foo (arg: &mut ()) -> &mut () {
23    let mut a_mut_binding: &mut _ = // …
24    # arg;
25    # type SomeRetType<'__> = &'__ mut ();
26    # let some_cond = || true;
27    # let some_other_cond = || true;
28    # use ::core::convert::identity as stuff;
29
30    //                                      the lifetime placeholder has to be
31    //                                          named `'polonius` !!
32    //                                               vvvvvvvvv
33    let x = polonius!(|a_mut_binding| -> SomeRetType<'polonius> {
34        let some_dependent_type = stuff(a_mut_binding);
35        if some_cond() {
36            polonius_return!(some_dependent_type);
37        }
38        if some_other_cond() {
39            exit_polonius!(42);
40            unreachable!();
41        }
42        42
43    });
44    assert_eq!(x, 42);
45    stuff(a_mut_binding) // macro gave it back
46    // …
47    # }
48    ``` */
49///
50/// ### Generic parameters
51///
52/// They Just Work™.
53///
54/**  - ```rust
55    use ::polonius_the_crab::prelude::*;
56
57    fn get_or_insert<'map, 'v, K, V : ?Sized> (
58        mut map: &'map mut ::std::collections::HashMap<K, &'v V>,
59        key: &'_ K,
60        fallback_value: &'v V,
61    ) -> &'map &'v V
62    where
63        K : ::core::hash::Hash + Eq + Clone,
64        V : ::core::fmt::Debug,
65    {
66        polonius!(|map| -> &'polonius &'v V {
67            if let Some(v) = map.get(key) {
68                dbg!(v);
69                polonius_return!(v);
70            }
71        });
72        map.insert(key.clone(), fallback_value);
73        &map[key]
74    }
75    ``` */
76#[macro_export]
77macro_rules! polonius {(
78    |$var:ident $(,)?| -> $Ret:ty
79        $body:block
80    $(,)?
81) => (
82    match
83        $crate::polonius::<
84            _,
85            _,
86            $crate::ForLt!(<'polonius> = $crate::ඞ::Dependent<$Ret>),
87        >(
88            $var,
89            |mut $var: &mut _| {
90                // silence the unused `mut` warning.
91                #[allow(clippy::self_assignment)] {
92                    $var = $var;
93                }
94                $crate::PoloniusResult::Owned(
95                    if true
96                        $body
97                    else {
98                        // avoid a dead-code warning
99                        $crate::ඞ::None.unwrap()
100                    }
101                )
102            },
103        )
104    {
105        | $crate::PoloniusResult::Borrowing(ret) => return ret.return_no_break(),
106        | $crate::PoloniusResult::Owned { value, input_borrow, .. } => {
107            $var = input_borrow;
108            value
109        },
110    }
111)}
112
113impl<T> ඞ::Dependent<T> {
114    pub
115    fn return_no_break (self)
116      -> T
117    {
118        match self {
119            | Self::Return(it) => it,
120            | Self::Break(unreachable) => match unreachable {},
121        }
122    }
123}
124
125/// See [`polonius!`] for more info.
126#[macro_export]
127macro_rules! polonius_return {( $e:expr $(,)? ) => (
128    return $crate::PoloniusResult::Borrowing($crate::ඞ::Dependent::Return($e))
129)}
130
131/// See [`polonius!`] for more info.
132#[macro_export]
133macro_rules! exit_polonius {( $($e:expr $(,)?)? ) => (
134    return $crate::PoloniusResult::Owned(
135        ($($e ,)? (),).0
136    )
137)}
138
139/// Perform the `?` operation inside a [`polonius!`] or [`polonius_loop!`] block.
140///
141///   - Only [`Result`] and [`Option`] are supported (_e.g._, no `ControlFlow`).
142///
143/// See [`polonius!`] for more info.
144///
145/// ## Example
146///
147/**  - ```rust
148    use {
149        ::polonius_the_crab::prelude::*,
150        ::std::collections::HashMap,
151    };
152
153    enum Error { /* … */ }
154
155    fn fallible_operation (value: &'_ i32)
156      -> Result<(), Error>
157    {
158        // …
159        # Ok(())
160    }
161
162    fn get_or_insert (
163        mut map: &'_ mut HashMap<i32, i32>,
164    ) -> Result<&'_ i32, Error>
165    {
166        polonius!(|map| -> Result<&'polonius i32, Error> {
167            if let Some(value) = map.get(&22) {
168                // fallible_operation(value)?;
169                polonius_try!(fallible_operation(value));
170                polonius_return!(Ok(value));
171            }
172        });
173        map.insert(22, 42);
174        Ok(&map[&22])
175    }
176    ``` */
177#[macro_export]
178macro_rules! polonius_try {( $e:expr $(,)? ) => (
179    match $crate::ඞ::Try::branch($e) {
180        | $crate::ඞ::Ok(it) => it,
181        | $crate::ඞ::Err(residual) => {
182            $crate::polonius_return!(
183                $crate::ඞ::Residual::with_output(residual)
184            )
185        },
186    }
187)}
188
189/// Convenience support for the `loop { … polonius!(…) }` pattern.
190///
191/// ### Example
192///
193/**  - ```rust
194    #![forbid(unsafe_code)]
195    use {
196        ::polonius_the_crab::{
197            prelude::*,
198        },
199        ::std::{
200            collections::HashMap,
201        },
202    };
203
204    enum Value {
205        Alive(i32),
206        Daed,
207    }
208
209    // Notice how this example, *despite its usage of the fancy `.entry()` API
210    // of `HashMap`s*, still needs `polonius_the_crab` to work!
211    fn get_first_alive_from_base_or_insert (
212        mut map: &'_ mut HashMap<usize, Value>,
213        base: usize,
214        default_value: i32,
215    ) -> &'_ i32
216    {
217        let mut idx = base;
218        // (loop {
219        polonius_loop!(|map| -> &'polonius i32 {
220            use ::std::collections::hash_map::*;
221            // return(
222            polonius_return!(
223                match map.entry(idx) {
224                    | Entry::Occupied(entry) => match entry.into_mut() {
225                        // Found a value!
226                        | &mut Value::Alive(ref val) => val,
227                        // "tombstone", keep searching
228                        | &mut Value::Daed => {
229                            idx += 1;
230                            // continue;
231                            polonius_continue!();
232                        },
233                    },
234                    | Entry::Vacant(slot) => match slot.insert(Value::Alive(default_value)) {
235                        | &mut Value::Alive(ref val) => val,
236                        | &mut Value::Daed => unreachable!(),
237                    },
238                }
239            );
240        });
241        unreachable!();
242    }
243    ``` */
244///
245/// <details class="custom"><summary>Error message without <code>::polonius_the_crab</code></summary>
246///
247/**  - ```rust ,compile_fail
248    # compile_error!("compiler error message"); /*
249    error[E0499]: cannot borrow `*map` as mutable more than once at a time
250      --> src/lib.rs:222:18
251       |
252    22 | mut map: &'_ mut HashMap<usize, Value>,
253       |          - let's call the lifetime of this reference `'1`
254    ...
255    33 |     match map.entry(idx) {
256       |           ^^^ `*map` was mutably borrowed here in the previous iteration of the loop
257    ...
258    45 |         | &mut Value::Alive(ref val) => val,
259       |                                         --- returning this value requires that `*map` be borrowed for `'1`
260    # */
261    ``` */
262///
263/// ___
264///
265/// </details>
266///
267/// ## `break`s
268///
269/// Whilst `return` and `continue`s inside a [`polonius_loop!`] invocation are
270/// quite straight-forward, `break` is actually more subtle and difficult
271/// to use.
272///
273/// <details class="custom"><summary><span class="summary-box"><span>Click to show</span></span></summary>
274///
275/// Indeed, compare the `break` semantics of the following two snippets:
276///
277/**  - ```rust ,ignore
278    let mut i = 0;
279    let found = loop {
280        match collection.get_mut(&i) {
281            Some(entry) => if entry.is_empty() {
282                break entry; // 👈
283            } else {
284                // …
285            },
286            None => i += 1,
287        }
288    };
289    ``` */
290///
291/// _vs._
292///
293/**  - ```rust ,ignore
294    let mut i = 0;
295    let position = loop {
296        match collection.get_mut(&i) {
297            Some(entry) => if entry.is_empty() {
298                break i; // 👈
299            } else {
300                // this requires polonius{,_the_crab} btw
301                return entry;
302            },
303            None => i += 1,
304        }
305    };
306    ``` */
307///
308/// With the former, we have a **dependent** / borrowing-from-`collection`
309/// `entry` value, which is the one we want to `break`:
310///
311///   - this requires `polonius{,_the_crab}` (independently of the presence of
312///     return-of-dependent-value statements);
313///
314/// Whereas with the latter, we are `break`ing `i`, an integer/index, that is,
315/// a **non-dependent** value.
316///
317///   - this wouldn't require `polonius{,_the_crab}` if it weren't for the
318///     `return entry` statement which does return a dependent item.
319///
320/// So, with the former, we can't use `collection` while `entry` is alive[^1] ,
321/// whereas with the latter we perfectly can.
322///
323/// All these differences, which are type-system-based, represent information
324/// which is unaccessible for the `polonius…!` family of macros, so a
325/// single/unified `polonius_break!` macro for both things, for instance, would
326/// be unable to make such a difference: unnecessary compile errors would then
327/// ensue!
328///
329/// The solution is then to feature not one but _two_ `break`-ing macros,
330/// depending on whether the value which we want to break **depends on/borrows**
331/// the `&'polonius mut`-borrowed state.
332///
333///   - If yes, use [`polonius_break_dependent!`];
334///
335///       - this, in turn, **requires an additional `'polonius`-infected
336///         `break` type annotation** for the proper lifetimes to come into play:
337///
338///         <code>[polonius_loop!]\(|var| -\> … <span style="color: green; font-weight: bolder;">, break: … {</span></code>
339///
340///   - Else, use [`polonius_break!`] \(in which case the `break` type annotation
341///     should not be used\).
342///
343/// ### Examples
344///
345/**  - ```rust
346    use {
347        ::polonius_the_crab::{
348            prelude::*,
349        },
350        ::std::{
351            collections::HashMap,
352        },
353    };
354
355    fn break_entry (mut coll: &'_ mut HashMap<i32, String>)
356      -> &'_ mut String
357    {
358        let mut i = 0;
359        //                                    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
360        let found = polonius_loop!(|coll| -> _, break: &'polonius mut String {
361            match coll.get_mut(&i) {
362                Some(entry) => if entry.is_empty() {
363                    polonius_break_dependent!(entry); // 👈
364                } else {
365                    // …
366                },
367                None => i += 1,
368            }
369        });
370        found.push('!');
371        found
372    }
373    ``` */
374///
375/// _vs._
376///
377/**  - ```rust
378    use {
379        ::polonius_the_crab::{
380            prelude::*,
381        },
382        ::std::{
383            collections::HashMap,
384        },
385    };
386
387    fn break_index (mut coll: &'_ mut HashMap<i32, String>)
388      -> &'_ mut String
389    {
390        let mut i = 0;
391        let position = polonius_loop!(|coll| -> &'polonius mut String {
392            match coll.get_mut(&i) {
393                Some(entry) => if entry.is_empty() {
394                    polonius_break!(i); // 👈
395                } else {
396                    polonius_return!(entry);
397                },
398                None => i += 1,
399            }
400        });
401        // Re-using `coll` is fine if not using the `dependent` flavor of break.
402        coll.get_mut(&i).unwrap()
403    }
404    ``` */
405///
406/// </details>
407///
408/// [^1]: In practice, with `polonius_break_dependent!` we won't be able to
409/// reuse `coll` anymore in the function. If this is a problem for you, you'll
410/// have no other choice but to refactor your loop into a smaller helper
411/// function so as to replace that `break` with a `return`.
412#[macro_export]
413macro_rules! polonius_loop {(
414    | $var:ident $(,)? | -> $Ret:ty $(, break: $Break:ty)?
415        $body:block
416    $(,)?
417) => (
418    loop {
419        match
420            $crate::polonius::<
421                _,
422                _,
423                $crate::ForLt!(<'polonius>
424                    = $crate::ඞ::Dependent< $Ret $(, $Break)? >
425                ),
426            >(
427                &mut *$var,
428                |mut $var: &mut _| {
429                    // silence the unused `mut` warning.
430                    #[allow(clippy::self_assignment)] {
431                        $var = $var;
432                    }
433                    let () =
434                        if true
435                            $body
436                        else {
437                            // avoid a dead-code warning
438                            $crate::ඞ::core::option::Option::None.unwrap()
439                        }
440                    ;
441                    $crate::polonius_continue!();
442                },
443            )
444        {
445            | $crate::PoloniusResult::Borrowing(dependent) => match dependent {
446                | $crate::ඞ::Dependent::Return(return_value) => return return_value,
447                | $crate::ඞ::Dependent::Break(break_value) => $crate::ඞ::first! {
448                    $((
449                        break if false { loop {} } else { break_value }
450                    ) (if $Break type else))? ({
451                        let _: $crate::ඞ::dependent_break_without_break_ty_annotation = break_value;
452                        match break_value {}
453                    })
454                },
455            },
456            | $crate::PoloniusResult::Owned { value, input_borrow, .. } => {
457                $var = input_borrow;
458                match value {
459                    | $crate::ඞ::core::ops::ControlFlow::Break(value) => {
460                        break if false { loop {} } else { value };
461                    },
462                    | $crate::ඞ::core::ops::ControlFlow::Continue(()) => continue,
463                }
464            },
465        }
466    }
467)}
468
469/// `break` a **non-dependent value** out of a [`polonius_loop!`].
470///
471///   - When the value to `break` with is **a dependent value** / a value that
472///     is _borrowing_ from the input, consider using
473///     [`polonius_break_dependent!`] instead.
474///
475/// ## Example
476///
477/**  - ```rust
478    use {
479        ::std::{
480            collections::HashMap,
481        },
482        ::polonius_the_crab::{
483            *,
484        },
485    };
486
487    fn example (mut map: &'_ mut HashMap<u8, i32>)
488      -> Option<&'_ mut i32>
489    {
490        let mut i = 0;
491        let x = polonius_loop!(|map| -> Option<&'polonius mut i32> {
492            if let Some(entry) = map.get_mut(&i) {
493                polonius_return!(Some(entry));
494            }
495            i += 1;
496            if i == 42 {
497                polonius_break!(i);
498            }
499        });
500        assert_eq!(x, i);
501        // Access to the "captured" `map` is still possible if using `polonius_break!`
502        // (and thus no `break: …` annotation on the "closure")
503        map.clear();
504        None
505    }
506    ``` */
507///
508#[macro_export]
509macro_rules! polonius_break {( $($e:expr $(,)?)? ) => (
510    return $crate::PoloniusResult::Owned(
511        $crate::ඞ::core::ops::ControlFlow::Break(
512            ($($e ,)? () ,).0
513        )
514    )
515)}
516
517/// `break` a **dependent value** out of a [`polonius_loop!`].
518///
519/// To be used in conjunction with a
520/// <code>[polonius_loop!]\(|var| -\> …<span style="color: green; font-weight: bolder;">, break: …</span> {</code> invocation.
521///
522///   - If the `, break: …` type annotation is forgotten, then invocations to
523///     `polonius_break_dependent!` will fail with an error message complaining
524///     about `cannot_use__polonius_break_dependentǃ__without_a_break_type_annotation_on__polonius_loopǃ`
525///
526/// ## Example
527///
528/**  - ```rust
529    use {
530        ::std::{
531            collections::HashMap,
532        },
533        ::polonius_the_crab::{
534            *,
535        },
536    };
537
538    fn example (mut map: &'_ mut HashMap<u8, i32>)
539    {
540        let mut i = 0;
541        //                              needed for `polonius_break_dependent!` to work.
542        //                                   vvvvvvvvvvvvvvvvvvvvvvvvvvv
543        let entry = polonius_loop!(|map| -> _, break: &'polonius mut i32 {
544        //                                             ^^^^^^^^^
545        //                                          don't forget the special annotation PoloniusResult.
546            if let Some(entry) = map.get_mut(&i) {
547                polonius_break_dependent!(entry);
548            }
549            i += 1;
550        });
551        // `map` was consumed by the loop, and is thus unusable.
552        // But the `break_dependent!`-yielded items is allowed to still be
553        // borrowing it.
554        *entry = 0;
555    }
556    ``` */
557///
558/// Now let's compare it to what happens when  [`polonius_break!`] is
559/// (incorrectly) used in its stead:
560///
561/// #### Incorrect usage
562///
563/// The following **fails to compile**:
564///
565/**  - ```rust ,compile_fail
566    use {
567        ::std::{
568            collections::HashMap,
569        },
570        ::polonius_the_crab::{
571            *,
572        },
573    };
574
575    fn example (mut map: &'_ mut HashMap<u8, i32>)
576    {
577        let mut i = 0;
578        let entry = polonius_loop!(|map| -> _ {
579            if let Some(entry) = map.get_mut(&i) {
580                polonius_break!(entry);
581            }
582            i += 1;
583        });
584        *entry = 0;
585    }
586    ``` */
587///
588///    with the following error message:
589///
590/**    ```rust, compile_fail
591    # compile_error!("compiler error message"); /*
592    error: lifetime may not live long enough
593      --> src/lib.rs:467:13
594       |
595    16 |       let entry = polonius_loop!(|map| -> _ {
596       |  _________________-
597    17 | |         if let Some(entry) = map.get_mut(&i) {
598    18 | |             polonius_break!(entry);
599       | |             ^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
600    19 | |         }
601    20 | |         i += 1;
602    21 | |     });
603       | |      -
604       | |      |
605       | |______let's call the lifetime of this reference `'1`
606       |        return type of closure is Result<Dependent<()>, ControlFlow<&'2 mut i32>>
607    # */
608    ``` */
609///
610///    Using `RUSTC_BOOTSTRAP=1 cargo rustc --profile-check -- -Zmacro-backtrace`
611///    to "improve" the error message, we can get:
612///
613/**    ```rust ,compile_fail
614    # compile_error!("compiler error message"); /*
615    error: lifetime may not live long enough
616       --> polonius-the-crab/src/lib.rs:442:12
617        |
618    351 |                    |mut $var: &mut _| {
619        |                               -     - return type of closure is Result<Dependent<()>, ControlFlow<&'2 mut i32>>
620        |                               |
621        |                               let's call the lifetime of this reference `'1`
622    ...
623    441 |  / macro_rules! polonius_break {( $($e:expr $(,)?)? ) => (
624    442 |  |     return $crate::ඞ::core::result::Result::Err(
625        |  |____________^
626    443 | ||         $crate::ඞ::core::ops::ControlFlow::Break(
627    444 | ||             ($($e ,)? () ,).0
628    445 | ||         )
629    446 | ||     )
630        | ||_____^ returning this value requires that `'1` must outlive `'2`
631    447 |  | )}
632        |  |__- in this expansion of `polonius_break!`
633        |
634       ::: src/lib.rs:552:13
635        |
636    18  |                polonius_break!(entry);
637        |                ----------------------- in this macro invocation
638    # */
639    ``` */
640///
641/// Which may be a bit better at hinting that we have a borrowing problem with
642/// `polonius_break!`, whereby the returned value cannot reach some borrowing /
643/// lifetime requirements (those stemming from an actually-dependent break
644/// value).
645#[macro_export]
646macro_rules! polonius_break_dependent {( $e:expr $(,)? ) => (
647    return $crate::PoloniusResult::Borrowing(
648        $crate::ඞ::Dependent::Break($e)
649    )
650)}
651
652/// `continue` to the next iteration of a [`polonius_loop!`].
653#[macro_export]
654macro_rules! polonius_continue {() => (
655    return $crate::PoloniusResult::Owned(
656        $crate::ඞ::core::ops::ControlFlow::<_>::Continue(())
657    )
658)}
659
660// macro internals
661#[doc(hidden)] /** Not part of the public API */ pub
662mod ඞ {
663    #![allow(nonstandard_style)]
664
665    pub use ::core::{self, prelude::v1::*};
666
667    pub use crate::r#try::{Try, Residual};
668
669    pub
670    enum cannot_use__polonius_break_dependentǃ__without_a_break_type_annotation_on__polonius_loopǃ
671    {}
672
673    pub
674    enum Dependent<Return, Break = Never> {
675        Return(Return),
676        Break(Break),
677    }
678
679    use {
680        cannot_use__polonius_break_dependentǃ__without_a_break_type_annotation_on__polonius_loopǃ
681        as
682        Never,
683    };
684
685    pub
686    type dependent_break_without_break_ty_annotation =
687        cannot_use__polonius_break_dependentǃ__without_a_break_type_annotation_on__polonius_loopǃ
688    ;
689
690    #[doc(hidden)] /** Not part of the public API */ #[macro_export]
691    macro_rules! ඞ_first {(
692        ( $($tt:tt)* )
693        $($rest:tt)*
694    ) => (
695        $($tt)*
696    )} pub use ඞ_first as first;
697}