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 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361
#![allow(rustdoc::redundant_explicit_links)] // (cargo-rdme needs this)
//! A rust-lang static analysis tool to automatically check for runtime borrow violations.
//!
//! ```rust
//! use autoken::MutableBorrow;
//!
//! fn foo() {
//! let _my_guard = MutableBorrow::<u32>::new();
//!
//! // Autoken statically issues a warning here because we attempted to call a function which could
//! // mutably borrow `u32` while we already have an active mutable borrow from `_my_guard`.
//! bar();
//! }
//!
//! fn bar() {
//! let _my_guard_2 = MutableBorrow::<u32>::new();
//! }
//! ```
//!
//! ```plain_text
//! warning: called a function expecting at most 0 mutable borrows of type u32 but was called in a scope with at least 1
//! --> src/main.rs:8:5
//! |
//! 8 | bar();
//! | ^^^^^
//! ````
//!
//! ## Checking Projects
//!
//! AuToken is a framework for adding static analysis of runtime borrowing to your crate. If you are
//! an end-user of a crate with integrations with AuToken and wish to check your project with the
//! tool, this is the section for you! If, instead, you're building a crate and wish to integrate with
//! AuToken, you should skip to the [Integrating AuToken](#integrating-autoken) section.
//!
//! If you wish to install this tool through `cargo`, you should run a command like:
//!
//! ```bash
//! cargo +nightly-2023-09-08 install cargo-autoken --version 0.1.0 -Z bindeps
//! ```
//!
//! This will likely require you to faff around with rustup toolchains. Because this process could
//! vary from user to user, the best instructions for setting up an appropriate toolchain are provided
//! by rustup, cargo, and rust.
//!
//! If you wish to install from source, assuming your current working directory is the same as the
//! [repository](https://github.com/radbuglet/autoken)'s README, `cargo-autoken` can be installed
//! like so:
//!
//! ```bash
//! cargo install --path src/cargo -Z bindeps
//! ```
//!
//! You can run AuToken validation on a target binary crate by running:
//!
//! ```bash
//! cargo autoken check
//! ```
//!
//! ...in its directory.
//!
//! Have fun!
//!
//! ## Ignoring False Positives
//!
//! AuToken is, by nature, very conservative. After all, its whole job is to ensure that only one
//! borrow of a given type exists at a given time, even if you're potentially borrowing from several
//! different sources at once!
//!
//! ```rust
//! # use autoken::MutableBorrow;
//! # struct MyCell<T> {
//! # _ty: core::marker::PhantomData<fn() -> T>,
//! # }
//! # impl<T> MyCell<T> {
//! # pub fn new(_value: T) -> Self {
//! # Self { _ty: core::marker::PhantomData }
//! # }
//! #
//! # pub fn borrow_mut(&self) -> MutableBorrow<T> {
//! # MutableBorrow::new()
//! # }
//! # }
//! let cell_1 = MyCell::new(1u32);
//! let cell_2 = MyCell::new(2u32);
//!
//! let borrow_1 = cell_1.borrow_mut();
//! let borrow_2 = cell_2.borrow_mut();
//! ```
//!
//! ```plain_text
//! warning: called a function expecting at most 0 mutable borrows of type u32 but was called in a scope with at least 1
//! --> src/main.rs:10:27
//! |
//! 10 | let borrow_2 = cell_2.borrow_mut();
//! | ^^^^^^^^^^^^
//! ```
//!
//! If you're sure you're doing something safe, you can ignore these warnings using the
//! [`assume_no_alias`](crate::assume_no_alias) method.
//!
//! ```rust
//! # use autoken::MutableBorrow;
//! # struct MyCell<T> {
//! # _ty: core::marker::PhantomData<fn() -> T>,
//! # }
//! # impl<T> MyCell<T> {
//! # pub fn new(_value: T) -> Self {
//! # Self { _ty: core::marker::PhantomData }
//! # }
//! #
//! # pub fn borrow_mut(&self) -> MutableBorrow<T> {
//! # MutableBorrow::new()
//! # }
//! # }
//! let cell_1 = MyCell::new(1u32);
//! let cell_2 = MyCell::new(2u32);
//!
//! let borrow_1 = cell_1.borrow_mut();
//! let borrow_2 = autoken::assume_no_alias(|| cell_2.borrow_mut());
//! ```
//!
//! See [`assume_no_alias_in`](crate::assume_no_alias_in) and [`assume_no_alias_in_many`](crate::assume_no_alias_in_many)
//! for more forms of this function.
//!
//! ### Making Sense of Control Flow Errors
//!
//! The weirdest diagnostic message you are likely to encounter while using AuToken is this one:
//!
//! ```
//! # use autoken::MutableBorrow;
//! # struct MyCell<T> {
//! # _ty: core::marker::PhantomData<fn() -> T>,
//! # }
//! # impl<T> MyCell<T> {
//! # pub fn new(_value: T) -> Self {
//! # Self { _ty: core::marker::PhantomData }
//! # }
//! #
//! # pub fn borrow_mut(&self) -> MutableBorrow<T> {
//! # MutableBorrow::new()
//! # }
//! # }
//! # let some_condition = true;
//! let cell_1 = MyCell::new(1u32);
//!
//! let my_borrow = if some_condition {
//! Some(cell_1.borrow_mut())
//! } else {
//! None
//! };
//! ```
//!
//! ```plain_text
//! warning: not all control-flow paths to this statement are guaranteed to borrow the same number of components
//! --> src/main.rs:9:21
//! |
//! 9 | let my_borrow = if some_condition {
//! | _____________________^
//! 10 | | Some(cell_1.borrow_mut())
//! 11 | | } else {
//! 12 | | None
//! 13 | | };
//! | |_____^
//! ```
//!
//! This error occurs because of a fundamental limitation of AuToken's design. AuToken analyzes your
//! programs by traversing through the control-flow graph `rustc` generates to analyze, among other
//! things, borrow checking. Every time it encounters a call to [`borrow_mutably`](crate::borrow_mutably)
//! or [`borrow_immutably`](crate::borrow_immutably), it increments the theoretical number of mutable
//! or immutable borrows a given control flow block may have and vice versa with
//! [`unborrow_mutably`](crate::unborrow_mutably) and [`unborrow_immutably`](crate::unborrow_immutably).
//! If there's a divergence in control flow as introduced by an `if` statement or a `loop`, AuToken
//! will visit and analyze each path separately.
//!
//! But what happens when those two paths join back together? How many borrows does a user have if
//! one path borrows `u32` mutably and the other doesn't borrow it at all? AuToken doesn't know the
//! answer to this question and just guesses randomly. Because this guess is probably wrong, it emits
//! a warning to tell you that it really can't handle code written like this.
//!
//! So, if this type of code can't be analyzed by AuToken, what can be done? The best solution is to
//! use a method AuToken integration writers are strongly encouraged to implement: `borrow_on_loan`
//! (or `borrow_mut_on_loan`, or `get_mut_on_loan`... just search for `_on_loan` in the docs!). This
//! method ties the borrow to an externally provided [`MutableBorrow`](crate::MutableBorrow) instance,
//! which should be defined outside of all the conditional logic.
//!
//! ```
//! # use autoken::{MutableBorrow, Nothing};
//! # struct MyCell<T> {
//! # _ty: core::marker::PhantomData<fn() -> T>,
//! # }
//! # impl<T> MyCell<T> {
//! # pub fn new(_value: T) -> Self {
//! # Self { _ty: core::marker::PhantomData }
//! # }
//! #
//! # pub fn borrow_mut_on_loan<'l>(&self, loaner: &'l mut MutableBorrow<T>) -> MutableBorrow<Nothing<'l>> {
//! # loaner.loan()
//! # }
//! # }
//! # let some_condition = true;
//! let cell_1 = MyCell::new(1u32);
//!
//! let mut guard = MutableBorrow::<u32>::new();
//! let my_borrow = if some_condition {
//! Some(cell_1.borrow_mut_on_loan(&mut guard))
//! } else {
//! None
//! };
//! ```
//!
//! If this is too hard to manage, you could also strip the token of all static borrow analysis
//! entirely using the [`strip_lifetime_analysis`](crate::MutableBorrow::strip_lifetime_analysis)
//! method. This is far more dangerous, however, because AuToken essentially forgets about the
//! existence of that borrow and potentially lets invalid borrows slip by.
//!
//! ```
//! # use autoken::MutableBorrow;
//! # struct MyCell<T> {
//! # _ty: core::marker::PhantomData<fn() -> T>,
//! # }
//! # impl<T> MyCell<T> {
//! # pub fn new(_value: T) -> Self {
//! # Self { _ty: core::marker::PhantomData }
//! # }
//! #
//! # pub fn borrow_mut(&self) -> MutableBorrow<T> {
//! # MutableBorrow::new()
//! # }
//! # }
//! # let some_condition = true;
//! let cell_1 = MyCell::new(1u32);
//!
//! let my_borrow = if some_condition {
//! Some(cell_1.borrow_mut().strip_lifetime_analysis())
//! } else {
//! None
//! };
//! ```
//!
//! Finally, if things get *really* bad, you could ignore the entire section with [`assume_black_box`](crate::assume_black_box).
//! This function is, very much, a last resort, because it prevents the static analysis tool from even
//! looking at anything in the called closure. You should read its documentation for details before
//! even thinking about touching it!
//!
//! ### Potential Borrows
//!
//! You may occasionally stumble across a fallible borrow method in your local AuToken-integrate crate
//! which takes in a [`PotentialMutableBorrow`](crate::PotentialMutableBorrow) or [`PotentialImmutableBorrow`](crate::PotentialImmutableBorrow)
//! "loaner" guard. The reason for these guards is somewhat similar to why we need loaner
//! guards for other conditionally created borrows with the added caveat that, because these borrow
//! guards are being used with a fallible borrow method, it is assumed that the aliasing with an
//! existing borrow can be handled gracefully at runtime. Because of this assumption,
//! `PotentialMutableBorrows` do not emit a warning if another confounding borrow guard is already
//! in scope.
//!
//! ```rust
//! # use {autoken::MutableBorrow, std::cell::{BorrowMutError, RefCell, RefMut}};
//! # #[derive(Debug)]
//! # struct MyRefMut<'a, T, B = T> {
//! # token: MutableBorrow<B>,
//! # sptr: RefMut<'a, T>,
//! # }
//! # use autoken::{Nothing, PotentialMutableBorrow};
//! # #[derive(Debug)]
//! # struct MyCell<T> {
//! # inner: RefCell<T>,
//! # }
//! # impl<T> MyCell<T> {
//! # pub fn new(value: T) -> Self {
//! # Self { inner: RefCell::new(value) }
//! # }
//! #
//! # pub fn try_borrow_mut<'l>(
//! # &self,
//! # loaner: &'l mut PotentialMutableBorrow<T>
//! # ) -> Result<MyRefMut<'_, T, Nothing<'l>>, BorrowMutError> {
//! # self.inner.try_borrow_mut().map(|sptr| MyRefMut {
//! # token: loaner.loan(),
//! # sptr,
//! # })
//! # }
//! # }
//! let my_cell = MyCell::new(1u32);
//!
//! let mut my_loaner_1 = PotentialMutableBorrow::<u32>::new();
//! let borrow_1 = my_cell.try_borrow_mut(&mut my_loaner_1).unwrap();
//!
//! // This should not trigger a static analysis warning because, if the specific cell is already
//! // borrowed, the function returns an `Err` rather than panicking.
//! let mut my_loaner_2 = PotentialMutableBorrow::<u32>::new();
//! let not_borrow_2 = my_cell.try_borrow_mut(&mut my_loaner_2).unwrap_err();
//! ```
//!
//! If the borrow cannot be handled gracefully, one may create a [`MutableBorrow`](crate::MutableBorrow)
//! or [`ImmutableBorrow`](crate::ImmutableBorrow) guard and [`downgrade`](crate::MutableBorrow::downgrade)
//! it to a `PotentialMutableBorrow` or `PotentialImmutableBorrow` guard so that the static analyzer
//! will start reporting these potentially problematic borrows again.
//!
//! ```no_run
//! # use {autoken::MutableBorrow, std::cell::{BorrowMutError, RefCell, RefMut}};
//! # #[derive(Debug)]
//! # struct MyRefMut<'a, T, B = T> {
//! # token: MutableBorrow<B>,
//! # sptr: RefMut<'a, T>,
//! # }
//! # use autoken::{Nothing, PotentialMutableBorrow};
//! # #[derive(Debug)]
//! # struct MyCell<T> {
//! # inner: RefCell<T>,
//! # }
//! # impl<T> MyCell<T> {
//! # pub fn new(value: T) -> Self {
//! # Self { inner: RefCell::new(value) }
//! # }
//! #
//! # pub fn try_borrow_mut<'l>(
//! # &self,
//! # loaner: &'l mut PotentialMutableBorrow<T>
//! # ) -> Result<MyRefMut<'_, T, Nothing<'l>>, BorrowMutError> {
//! # self.inner.try_borrow_mut().map(|sptr| MyRefMut {
//! # token: loaner.loan(),
//! # sptr,
//! # })
//! # }
//! # }
//! let my_cell = MyCell::new(1u32);
//!
//! let mut my_loaner_1 = PotentialMutableBorrow::<u32>::new();
//! let borrow_1 = my_cell.try_borrow_mut(&mut my_loaner_1).unwrap();
//!
//! // Unlike the previous example, this code cannot handle aliasing borrows gracefully, so we should
//! // create a `MutableBorrow` first to get the alias check and then downgrade it for use in the
//! // fallible borrowing method.
//! let mut my_loaner_2 = MutableBorrow::<u32>::new().downgrade();
//! let not_borrow_2 = my_cell.try_borrow_mut(&mut my_loaner_2).unwrap();
//! ```
//!
//! ## Dealing With Dynamic Dispatches
//!
//! AuToken resolves dynamic dispatches by collecting all possible dispatch targets ahead of time
//! based around what gets unsized to what and assumes that any of those concrete types could be
//! called by an invocation of a given unsized type. This can occasionally be overly pessimistic.
//! You can help this along by making the dynamically dispatched traits more fine grained. For
//! example, instead of using an `FnMut(u32, i32, f32)`, you could use an
//! `FnMut(PhantomData<MyHandlers>, u32, i32, f32)`. Likewise, if you have a trait `MyBehavior`, you
//! could parameterize it by a marker generic type to make it even more fine-grained.
//!
//! If something is really wrong, you could, once again, use [`assume_black_box`](crate::assume_black_box)
//! to hide the unsizing coercions that create these dynamic dispatch targets. Once again, this is,
//! very much, a last resort and you should certainly read its documentation for details before even
//! thinking about touching it!
//!
//! ## Dealing With Foreign Code
//!
//! AuToken has no clue how to deal with foreign code and just ignores it. If you have a foreign
//! function that calls back into userland code, you can tell AuToken that the code is, indeed,
//! reachable with something like this:
//!
//! ```
//! # fn my_ffi_call(f: impl FnOnce()) {}
//! # fn my_callback() {}
//! my_ffi_call(my_callback);
//!
//! if false { // reachability hint to AuToken
//! my_callback();
//! }
//! ```
//!
//! # Integrating AuToken
//!
//! This section is for crate developers wishing to add static analysis to their dynamic borrowing
//! schemes. If you're interested in using one of those crates, see the [checking projects](#checking-projects)
//! section.
//!
//! There are four primitive borrowing functions offered by this library:
//!
//! - [`borrow_mutably<T>`](crate::borrow_mutably)
//! - [`borrow_immutably<T>`](crate::borrow_immutably)
//! - [`unborrow_mutably<T>`](crate::unborrow_mutably)
//! - [`unborrow_immutably<T>`](crate::unborrow_immutably)
//!
//! These functions, in reality, do absolutely nothing and are compiled away. However, when checked
//! by the custom AuToken rustc wrapper, they virtually "borrow" and "unborrow" a global token of
//! the type `T` and raise a warning if it is possible to violate the XOR mutability rules of that
//! virtual global token.
//!
//! Usually, these functions aren't called directly and are instead called indirectly through their
//! RAII'd counterparts [`MutableBorrow`](crate::MutableBorrow) and [`ImmutableBorrow`](crate::ImmutableBorrow).
//!
//! These primitives can be used to introduce additional compile-time safety to dynamically checked
//! borrowing and locking schemes. Here's a couple of examples:
//!
//! You could make a safe wrapper around a `RefCell`...
//!
//! ```no_run
//! use autoken::MutableBorrow;
//! use std::cell::{RefCell, RefMut};
//!
//! struct MyRefCell<T> {
//! inner: RefCell<T>,
//! }
//!
//! impl<T> MyRefCell<T> {
//! pub fn new(value: T) -> Self {
//! Self { inner: RefCell::new(value) }
//! }
//!
//! pub fn borrow_mut(&self) -> MyRefMut<'_, T> {
//! MyRefMut {
//! token: MutableBorrow::new(),
//! sptr: self.inner.borrow_mut(),
//! }
//! }
//! }
//!
//! struct MyRefMut<'a, T> {
//! token: MutableBorrow<T>,
//! sptr: RefMut<'a, T>,
//! }
//!
//! let my_cell = MyRefCell::new(1u32);
//! let _a = my_cell.borrow_mut();
//!
//! // This second mutable borrow results in an AuToken warning.
//! let _b = my_cell.borrow_mut();
//! ```
//!
//! ```plain_text
//! warning: called a function expecting at most 0 mutable borrows of type u32 but was called in a scope with at least 1
//! --> src/main.rs:33:22
//! |
//! 33 | let _b = my_cell.borrow_mut();
//! | ^^^^^^^^^^^^
//! ````
//!
//! You could make a reentrancy-protected function...
//!
//! ```rust
//! fn do_not_reenter(f: impl FnOnce()) {
//! struct ISaidDoNotReenter;
//!
//! let _guard = autoken::MutableBorrow::<ISaidDoNotReenter>::new();
//! f();
//! }
//!
//! do_not_reenter(|| {
//! // Whoops!
//! do_not_reenter(|| {});
//! });
//! ```
//!
//! ```plain_text
//! warning: called a function expecting at most 0 mutable borrows of type main::do_not_reenter::ISaidDoNotReenter but was called in a scope with at least 1
//! --> src/main.rs:6:9
//! |
//! 6 | f();
//! | ^^^
//! ```
//!
//! You could even deny an entire class of functions where calling them would be dangerous!
//!
//! ```rust
//! use autoken::{ImmutableBorrow, MutableBorrow};
//!
//! struct IsOnMainThread;
//!
//! fn begin_multithreading(f: impl FnOnce()) {
//! let _guard = MutableBorrow::<IsOnMainThread>::new();
//! f();
//! }
//!
//! fn only_call_me_on_main_thread() {
//! let _guard = ImmutableBorrow::<IsOnMainThread>::new();
//! // ...
//! }
//!
//! begin_multithreading(|| {
//! // Whoops!
//! only_call_me_on_main_thread();
//! });
//! ```
//!
//! ```plain_text
//! warning: called a function expecting at most 0 mutable borrows of type main::IsOnMainThread but was called in a scope with at least 1
//! --> src/main.rs:6:9
//! |
//! 6 | f();
//! | ^^^
//! ```
//!
//! Pretty neat, huh.
//!
//! ## Dealing with Limitations
//!
//! If you read the [checking projects](#checking-projects) section like I asked you not to, you'd
//! hear about four pretty major limitations of AuToken. While most of these limitations can be overcome
//! by tools provided by AuToken, the second limitation—[Control Flow Errors](#making-sense-of-control-flow-errors)—
//! requires a bit of help from developers wishing to integrate with AuToken. You are strongly
//! encouraged to read that section before this section, since it motivates the necessity for these
//! special method variants.
//!
//! In summary:
//!
//! 1. For every guard object, provide a `strip_lifetime_analysis` function similar to
//! [`MutableBorrow`](crate::MutableBorrow::strip_lifetime_analysis)'s.
//! 2. For every guard object, provide a way to acquire that object with a "loaner" borrow object. The
//! recommended suffix for this variant is `on_loan`. The mechanism for doing so is likely very
//! similar to `MutableBorrow`'s [`loan`](crate::MutableBorrow::loan) method.
//! 3. For conditional borrow methods which check their borrow before performing it, the method should
//! be made to loan a [`PotentialMutableBorrow`](crate::PotentialMutableBorrow) or [`PotentialImmutableBorrow`](crate::PotentialImmutableBorrow)
//! instead.
//!
//! All of these methods rely on being able to convert the RAII guard's type from its originally
//! borrowed type to [`Nothing`](crate::Nothing)—a special marker type in AuToken which indicates that
//! the borrow guard isn't actually borrowing anything. Doing this requires you to keep track of the
//! borrowed type at the type level since AuToken lacks the power to analyze runtime mechanisms for
//! doing that. Here's an example of how to accomplish this:
//!
//! ```rust
//! # use {autoken::MutableBorrow, std::cell::RefMut};
//! struct MyRefMut<'a, T, B = T> {
//! // ^ notice the addition of this special parameter?
//! token: MutableBorrow<B>,
//! sptr: RefMut<'a, T>,
//! }
//! ```
//!
//! With that additional parameter in place, we can implement the first required method: `strip_lifetime_analysis`.
//! Its implementation is relatively straightforward:
//!
//! ```rust
//! # use {autoken::MutableBorrow, std::cell::{RefCell, RefMut}};
//! # struct MyRefCell<T> {
//! # inner: RefCell<T>,
//! # }
//! #
//! # impl<T> MyRefCell<T> {
//! # pub fn new(value: T) -> Self {
//! # Self { inner: RefCell::new(value) }
//! # }
//! #
//! # pub fn borrow_mut(&self) -> MyRefMut<'_, T> {
//! # MyRefMut {
//! # token: MutableBorrow::new(),
//! # sptr: self.inner.borrow_mut(),
//! # }
//! # }
//! # }
//! use autoken::Nothing;
//!
//! struct MyRefMut<'a, T, B = T> {
//! token: MutableBorrow<B>,
//! sptr: RefMut<'a, T>,
//! }
//!
//! impl<'a, T, B> MyRefMut<'a, T, B> {
//! pub fn strip_lifetime_analysis(self) -> MyRefMut<'a, T, Nothing<'static>> {
//! MyRefMut {
//! token: self.token.strip_lifetime_analysis(),
//! sptr: self.sptr,
//! }
//! }
//! }
//!
//! # let my_condition = true;
//! let my_cell = MyRefCell::new(1u32);
//! let my_guard = if my_condition {
//! Some(my_cell.borrow_mut().strip_lifetime_analysis())
//! } else {
//! None
//! };
//! ```
//!
//! The `'static` lifetime in `Nothing` doesn't really mean anything. Indeed, the lifetime in `Nothing`
//! is purely a convenience lifetime whose utility will become more clear when we implement the second
//! required method: `borrow_mut_on_loan`.
//!
//! Writing this method is also relatively straightforward:
//!
//! ```rust
//! # use {autoken::MutableBorrow, std::cell::{RefCell, RefMut}};
//! # struct MyRefMut<'a, T, B = T> {
//! # token: MutableBorrow<B>,
//! # sptr: RefMut<'a, T>,
//! # }
//! use autoken::Nothing;
//!
//! struct MyRefCell<T> {
//! inner: RefCell<T>,
//! }
//!
//! impl<T> MyRefCell<T> {
//! # pub fn new(value: T) -> Self {
//! # Self { inner: RefCell::new(value) }
//! # }
//! pub fn borrow_mut_on_loan<'l>(
//! &self,
//! loaner: &'l mut MutableBorrow<T>
//! ) -> MyRefMut<'_, T, Nothing<'l>> {
//! MyRefMut {
//! token: loaner.loan(),
//! sptr: self.inner.borrow_mut(),
//! }
//! }
//! }
//!
//! # let my_condition = true;
//! let my_cell = MyRefCell::new(1u32);
//!
//! let mut my_loaner = MutableBorrow::<u32>::new();
//! let my_guard = if my_condition {
//! Some(my_cell.borrow_mut_on_loan(&mut my_loaner))
//! } else {
//! None
//! };
//! ```
//!
//! Here, we're using the placeholder lifetime in `Nothing` to limit the lifetime of the loans to
//! the reference to the `loaner`. Pretty convenient.
//!
//! Finally, fallible `borrow` method variants can be implemented in a way almost identical to the
//! previous example's:
//!
//! ```rust
//! # use {autoken::MutableBorrow, std::cell::{BorrowMutError, RefCell, RefMut}};
//! # #[derive(Debug)]
//! # struct MyRefMut<'a, T, B = T> {
//! # token: MutableBorrow<B>,
//! # sptr: RefMut<'a, T>,
//! # }
//! use autoken::{Nothing, PotentialMutableBorrow};
//!
//! # #[derive(Debug)]
//! struct MyRefCell<T> {
//! inner: RefCell<T>,
//! }
//!
//! impl<T> MyRefCell<T> {
//! # pub fn new(value: T) -> Self {
//! # Self { inner: RefCell::new(value) }
//! # }
//! pub fn try_borrow_mut<'l>(
//! &self,
//! loaner: &'l mut PotentialMutableBorrow<T>
//! ) -> Result<MyRefMut<'_, T, Nothing<'l>>, BorrowMutError> {
//! self.inner.try_borrow_mut().map(|sptr| MyRefMut {
//! token: loaner.loan(),
//! sptr,
//! })
//! }
//! }
//!
//! let my_cell = MyRefCell::new(1u32);
//!
//! let mut my_loaner_1 = PotentialMutableBorrow::<u32>::new();
//! let borrow_1 = my_cell.try_borrow_mut(&mut my_loaner_1).unwrap();
//!
//! let mut my_loaner_2 = PotentialMutableBorrow::<u32>::new();
//! let not_borrow_2 = my_cell.try_borrow_mut(&mut my_loaner_2).unwrap_err();
//! ```
//!
//! How exciting!
#![no_std]
use core::{cmp::Ordering, fmt, marker::PhantomData, mem};
// === Primitives === //
/// Virtually acquires a mutable reference to a global token of type `T`.
///
/// This method is more typically called through the [`MutableBorrow`] guard's constructor.
///
/// In regular builds, this does nothing, but when AuToken checks a given binary, it uses calls to
/// functions like this to determine whether a program has the possibility of virtually borrowing a
/// global token in a way which violates XOR borrowing rules.
///
/// Global token identity is lifetime-erased (i.e. `&'a u32` and `&'b u32` always refer to the same
/// virtual global token). When `T` is [`Nothing`], nothing happens.
pub const fn borrow_mutably<T: ?Sized>() {
const fn __autoken_borrow_mutably<T: ?Sized>() {}
__autoken_borrow_mutably::<T>();
}
/// Virtually acquires an immutable reference to a global token of type `T`.
///
/// This method is more typically called through the [`ImmutableBorrow`] guard's constructor.
///
/// In regular builds, this does nothing, but when AuToken checks a given binary, it uses calls to
/// functions like this to determine whether a program has the possibility of virtually borrowing a
/// global token in a way which violates XOR borrowing rules.
///
/// Global token identity is lifetime-erased (i.e. `&'a u32` and `&'b u32` always refer to the same
/// virtual global token). When `T` is [`Nothing`], nothing happens.
pub const fn borrow_immutably<T: ?Sized>() {
const fn __autoken_borrow_immutably<T: ?Sized>() {}
__autoken_borrow_immutably::<T>();
}
/// Virtually unacquires a mutable reference to a global token of type `T`.
///
/// This method is more typically called through the [`MutableBorrow`] guard's destructor.
///
/// In regular builds, this does nothing, but when AuToken checks a given binary, it uses calls to
/// functions like this to determine whether a program has the possibility of virtually borrowing a
/// global token in a way which violates XOR borrowing rules.
///
/// Global token identity is lifetime-erased (i.e. `&'a u32` and `&'b u32` always refer to the same
/// virtual global token). When `T` is [`Nothing`], nothing happens.
pub const fn unborrow_mutably<T: ?Sized>() {
const fn __autoken_unborrow_mutably<T: ?Sized>() {}
__autoken_unborrow_mutably::<T>();
}
/// Virtually unacquires an immutable reference to a global token of type `T`.
///
/// This method is more typically called through the [`ImmutableBorrow`] guard's destructor.
///
/// In regular builds, this does nothing, but when AuToken checks a given binary, it uses calls to
/// functions like this to determine whether a program has the possibility of virtually borrowing a
/// global token in a way which violates XOR borrowing rules.
///
/// Global token identity is lifetime-erased (i.e. `&'a u32` and `&'b u32` always refer to the same
/// virtual global token). When `T` is [`Nothing`], nothing happens.
pub const fn unborrow_immutably<T: ?Sized>() {
const fn __autoken_unborrow_immutably<T: ?Sized>() {}
__autoken_unborrow_immutably::<T>();
}
/// Ensures that it is possible to virtually acquire a mutable borrow of the global token of type `T`.
///
/// In regular builds, this does nothing, but when AuToken checks a given binary, it uses calls to
/// functions like this to determine whether a program has the possibility of virtually borrowing a
/// global token in a way which violates XOR borrowing rules.
///
/// Global token identity is lifetime-erased (i.e. `&'a u32` and `&'b u32` always refer to the same
/// virtual global token). When `T` is [`Nothing`], nothing happens.
pub const fn assert_mutably_borrowable<T: ?Sized>() {
borrow_mutably::<T>();
unborrow_mutably::<T>();
}
/// Ensures that it is possible to virtually acquire an immutable borrow of the global token of type `T`.
///
/// In regular builds, this does nothing, but when AuToken checks a given binary, it uses calls to
/// functions like this to determine whether a program has the possibility of virtually borrowing a
/// global token in a way which violates XOR borrowing rules.
///
/// Global token identity is lifetime-erased (i.e. `&'a u32` and `&'b u32` always refer to the same
/// virtual global token). When `T` is [`Nothing`], nothing happens.
pub const fn assert_immutably_borrowable<T: ?Sized>() {
borrow_immutably::<T>();
unborrow_immutably::<T>();
}
/// Asserts that the provided closure's virtual borrows to tokens of type `(T_1, ..., T_n)` will not
/// cause any aliasing issues at runtime.
///
/// `T` must be a tuple of token types to ignore. Its maximum supported arity is 12.
///
/// In regular builds, this does nothing, but when AuToken checks a given binary, it uses calls to
/// functions like this to determine whether a program has the possibility of virtually borrowing a
/// global token in a way which violates XOR borrowing rules.
///
/// Global token identity is lifetime-erased (i.e. `&'a u32` and `&'b u32` always refer to the same
/// virtual global token). When a component in `T` is [`Nothing`], it is effectively ignored.
pub fn assume_no_alias_in_many<T, Res>(f: impl FnOnce() -> Res) -> Res
where
T: ?Sized + tuple_sealed::Tuple,
{
#[allow(clippy::extra_unused_type_parameters)] // Used by autoken
fn __autoken_assume_no_alias_in<T: ?Sized, Res>(f: impl FnOnce() -> Res) -> Res {
f()
}
__autoken_assume_no_alias_in::<T, Res>(f)
}
/// Asserts that the provided closure's virtual borrows to tokens of type `T` will not cause any
/// aliasing issues at runtime.
///
/// In regular builds, this does nothing, but when AuToken checks a given binary, it uses calls to
/// functions like this to determine whether a program has the possibility of virtually borrowing a
/// global token in a way which violates XOR borrowing rules.
///
/// Global token identity is lifetime-erased (i.e. `&'a u32` and `&'b u32` always refer to the same
/// virtual global token). When `T` is [`Nothing`], nothing happens.
pub fn assume_no_alias_in<T: ?Sized, Res>(f: impl FnOnce() -> Res) -> Res {
assume_no_alias_in_many::<(T,), Res>(f)
}
/// Asserts that the provided closure's virtual borrows to any token will not cause any aliasing
/// issues at runtime.
///
/// In regular builds, this does nothing, but when AuToken checks a given binary, it uses calls to
/// functions like this to determine whether a program has the possibility of virtually borrowing a
/// global token in a way which violates XOR borrowing rules.
pub fn assume_no_alias<Res>(f: impl FnOnce() -> Res) -> Res {
fn __autoken_assume_no_alias<Res>(f: impl FnOnce() -> Res) -> Res {
f()
}
__autoken_assume_no_alias::<Res>(f)
}
/// Tells the AuToken static analyzer to entirely ignore the body of the provided closure. This should
/// be a last resort for when nothing else works out.
///
/// This prevents both enumeration of unsizing coercions performed by the closure (which contribute
/// to the set of potential dynamic dispatch targets for a given function pointer or trait type) and
/// detection of the various `borrow` and `unborrow` function calls. This can be particularly tricky
/// if you return a guard from the black-boxed closure since, although the call to [`borrow_mutably`]
/// was ignored, the call to [`unborrow_mutably`] in the destructor is not:
///
/// ```rust
/// use autoken::MutableBorrow;
///
/// // The call to `borrow_mutably` was just ignored.
/// let guard = autoken::assume_black_box(|| MutableBorrow::<u32>::new());
///
/// // ...but the call to `unborrow_mutably` was not!
/// drop(guard);
///
/// // Autoken now thinks that we have -1 mutable borrows in scope!
/// ```
///
/// If we want to fix this, we need to make sure to `strip_lifetime_analysis` on all the guards we
/// return:
///
/// ```rust
/// use autoken::MutableBorrow;
///
/// // The call to `borrow_mutably` was just ignored.
/// let guard = autoken::assume_black_box(|| {
/// MutableBorrow::<u32>::new().strip_lifetime_analysis()
/// });
///
/// // Luckily, in stripping its lifetime analysis, it no longer calls `unborrow_mutably` here.
/// drop(guard);
///
/// // Autoken now has an accurate idea of the number of guards in scope.
/// ```
///
/// It bears repeating that this function is super dangerous. Please consider all the alternatives
/// listed in the crate's [Ignoring False Positives](index.html#ignoring-false-positives) and
/// [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors) section before
/// even thinking about reaching for this function!
///
/// In regular builds, this does nothing, but when AuToken checks a given binary, it uses calls to
/// functions like this to determine whether a program has the possibility of virtually borrowing a
/// global token in a way which violates XOR borrowing rules.
pub fn assume_black_box<T>(f: impl FnOnce() -> T) -> T {
fn __autoken_assume_black_box<T>(f: impl FnOnce() -> T) -> T {
f()
}
__autoken_assume_black_box::<T>(f)
}
/// A marker type representing a borrow of... "nothing."
///
/// When passed as a parameter to any borrow-adjacent function or method in this crate, this type
/// essentially turns that operation into a no-op. The lifetime is merely a placeholder to help with
/// the common idioms detailed in the [Dealing with Limitations](index.html#dealing-with-limitations)
/// section of the integration guide.
///
/// This is useful for disabling borrows for a given RAII'd AuToken object, as needed by
/// `strip_lifetime_analysis` or for tying an object's borrow to a different [`MutableBorrow`] or
/// [`ImmutableBorrow`] guard.
///
/// An instance of this type cannot be obtained—it is a marker type.
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct Nothing<'a> {
__autoken_nothing_type_field_indicator: PhantomData<&'a ()>,
}
mod tuple_sealed {
pub trait Tuple {}
impl<A: ?Sized> Tuple for (A,) {}
impl<A, B: ?Sized> Tuple for (A, B) {}
impl<A, B, C: ?Sized> Tuple for (A, B, C) {}
impl<A, B, C, D: ?Sized> Tuple for (A, B, C, D) {}
impl<A, B, C, D, E: ?Sized> Tuple for (A, B, C, D, E) {}
impl<A, B, C, D, E, F: ?Sized> Tuple for (A, B, C, D, E, F) {}
impl<A, B, C, D, E, F, G: ?Sized> Tuple for (A, B, C, D, E, F, G) {}
impl<A, B, C, D, E, F, G, H: ?Sized> Tuple for (A, B, C, D, E, F, G, H) {}
impl<A, B, C, D, E, F, G, H, I: ?Sized> Tuple for (A, B, C, D, E, F, G, H, I) {}
impl<A, B, C, D, E, F, G, H, I, J: ?Sized> Tuple for (A, B, C, D, E, F, G, H, I, J) {}
impl<A, B, C, D, E, F, G, H, I, J, K: ?Sized> Tuple for (A, B, C, D, E, F, G, H, I, J, K) {}
impl<A, B, C, D, E, F, G, H, I, J, K, L: ?Sized> Tuple for (A, B, C, D, E, F, G, H, I, J, K, L) {}
}
// === Guaranteed RAII === //
/// A guard for a virtual mutable borrow of the global token of type `T`.
///
/// These can be thought of as [`Ref`](core::cell::Ref)s to those global tokens except that they have
/// no impact on the runtime and only contribute to AuToken's static analysis of the binary.
///
/// As with [`borrow_mutably`] and friends, setting `T` to [`Nothing`] causes this guard to have no
/// effect on the statically-analyzed borrow counts.
///
/// Developers wishing to integrate their crate with AuToken will likely use this type to represent
/// the static counterpart to a runtime borrow of some cell of type `T` as described in the
/// [Integrating AuToken](index.html#integrating-autoken) section of the crate documentation.
///
/// End-users consuming crates with integrations with AuToken, meanwhile, will likely only use these
/// guards for loaned borrows as described by the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation.
pub struct MutableBorrow<T: ?Sized> {
_ty: PhantomData<fn() -> T>,
}
impl<T: ?Sized> MutableBorrow<T> {
/// Constructs a new `MutableBorrow` guard.
///
/// This function has no runtime cost but will cause the AuToken static analyzer to report
/// potential virtual borrowing issues with other guards.
///
/// Internally, this function just calls [`borrow_mutably`] with the provided type `T`.
pub const fn new() -> Self {
borrow_mutably::<T>();
Self { _ty: PhantomData }
}
/// Transforms this `MutableBorrow` into a [`PotentialMutableBorrow`] of the same type.
pub fn downgrade(self) -> PotentialMutableBorrow<T> {
PotentialMutableBorrow(self)
}
/// Transforms a reference to `MutableBorrow` into a reference to a [`PotentialMutableBorrow`] of
/// the same type.
pub fn downgrade_ref(&self) -> &PotentialMutableBorrow<T> {
unsafe { mem::transmute(self) }
}
/// Transforms a mutable reference to `MutableBorrow` into a mutable reference to a [`PotentialMutableBorrow`]
/// of the same type.
pub fn downgrade_mut(&mut self) -> &mut PotentialMutableBorrow<T> {
unsafe { mem::transmute(self) }
}
/// Creates a loaned `MutableBorrow` of this guard which has no effect on the static analysis
/// borrow counters by itself, making it safe to use in conditional code.
///
/// See the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation for more details on loans.
pub fn loan(&mut self) -> MutableBorrow<Nothing<'_>> {
MutableBorrow::new()
}
/// Creates a loaned `MutableBorrow` of this guard which has no effect on the static analysis
/// borrow counters by itself, making it safe to use in conditional code.
///
/// Unlike [`loan`](MutableBorrow::loan), this method takes an immutable reference to the loaning
/// `MutableBorrow`, which makes it more prone to accidental borrow aliasing.
///
/// See the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation for more details on loans.
pub fn assume_no_alias_loan(&self) -> MutableBorrow<Nothing<'_>> {
MutableBorrow::new()
}
/// Clones the current `MutableBorrow` instance and assumes that it is safe to do so.
pub fn assume_no_alias_clone(&self) -> Self {
assume_no_alias(|| Self::new())
}
/// Transforms the type of `T` into [`Nothing`], effectively making it as if this borrow guard no
/// longer exists.
///
/// See the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation for more details on the utility of `strip_lifetime_analysis`.
pub fn strip_lifetime_analysis(self) -> MutableBorrow<Nothing<'static>> {
drop(self);
MutableBorrow::new()
}
}
impl<T: ?Sized> Default for MutableBorrow<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: ?Sized> fmt::Debug for MutableBorrow<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MutableBorrow").finish_non_exhaustive()
}
}
impl<T: ?Sized> Eq for MutableBorrow<T> {}
impl<T: ?Sized> PartialEq for MutableBorrow<T> {
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl<T: ?Sized> Ord for MutableBorrow<T> {
fn cmp(&self, _other: &Self) -> Ordering {
Ordering::Equal
}
}
impl<T: ?Sized> PartialOrd for MutableBorrow<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: ?Sized> Drop for MutableBorrow<T> {
fn drop(&mut self) {
unborrow_mutably::<T>();
}
}
/// A guard for a virtual immutable borrow of the global token of type `T`.
///
/// These can be thought of as [`Ref`](core::cell::Ref)s to those global tokens except that they have
/// no impact on the runtime and only contribute to AuToken's static analysis of the binary.
///
/// As with [`borrow_mutably`] and friends, setting `T` to [`Nothing`] causes this guard to have no
/// effect on the statically-analyzed borrow counts.
///
/// Developers wishing to integrate their crate with AuToken will likely use this type to represent
/// the static counterpart to a runtime borrow of some cell of type `T` as described in the
/// [Integrating AuToken](index.html#integrating-autoken) section of the crate documentation.
///
/// End-users consuming crates with integrations with AuToken, meanwhile, will likely only use these
/// guards for loaned borrows as described by the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation.
pub struct ImmutableBorrow<T: ?Sized> {
_ty: PhantomData<fn() -> T>,
}
impl<T: ?Sized> ImmutableBorrow<T> {
/// Constructs a new `ImmutableBorrow` guard.
///
/// This function has no runtime cost but will cause the AuToken static analyzer to report
/// potential virtual borrowing issues with other guards.
///
/// Internally, this function just calls [`borrow_immutably`] with the provided type `T`.
pub const fn new() -> Self {
borrow_immutably::<T>();
Self { _ty: PhantomData }
}
/// Transforms this `ImmutableBorrow` into a [`PotentialImmutableBorrow`] of the same type.
pub fn downgrade(self) -> PotentialImmutableBorrow<T> {
PotentialImmutableBorrow(self)
}
/// Transforms a reference to `ImmutableBorrow` into a reference to a [`PotentialImmutableBorrow`]
/// of the same type.
pub fn downgrade_ref(&self) -> &PotentialImmutableBorrow<T> {
unsafe { mem::transmute(self) }
}
/// Transforms a mutable reference to `ImmutableBorrow` into a mutable reference to a [`PotentialImmutableBorrow`]
/// of the same type.
pub fn downgrade_mut(&mut self) -> &mut PotentialImmutableBorrow<T> {
unsafe { mem::transmute(self) }
}
/// Creates a loaned `ImmutableBorrow` of this guard which has no effect on the static analysis
/// borrow counters by itself, making it safe to use in conditional code.
///
/// See the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation for more details on loans.
pub const fn loan(&self) -> ImmutableBorrow<Nothing<'_>> {
ImmutableBorrow::new()
}
/// Transforms the type of `T` into [`Nothing`], effectively making it as if this borrow guard no
/// longer exists.
///
/// See the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation for more details on the utility of `strip_lifetime_analysis`.
pub fn strip_lifetime_analysis(self) -> ImmutableBorrow<Nothing<'static>> {
drop(self);
ImmutableBorrow::new()
}
}
impl<T: ?Sized> Default for ImmutableBorrow<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: ?Sized> fmt::Debug for ImmutableBorrow<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ImmutableBorrow").finish_non_exhaustive()
}
}
impl<T: ?Sized> Eq for ImmutableBorrow<T> {}
impl<T: ?Sized> PartialEq for ImmutableBorrow<T> {
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl<T: ?Sized> Ord for ImmutableBorrow<T> {
fn cmp(&self, _other: &Self) -> Ordering {
Ordering::Equal
}
}
impl<T: ?Sized> PartialOrd for ImmutableBorrow<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: ?Sized> Clone for ImmutableBorrow<T> {
fn clone(&self) -> Self {
Self::new()
}
}
impl<T: ?Sized> Drop for ImmutableBorrow<T> {
fn drop(&mut self) {
unborrow_immutably::<T>();
}
}
// === Potential RAII === //
/// A variant of [`MutableBorrow`] which represents a mutable borrow which can gracefully recover from
/// borrow errors if they end up occurring.
///
/// Unlike a `MutableBorrow`, this token will not trigger a warning if a confounding borrow is
/// potentially alive at the same time as it since, if the dynamic borrow this borrow guard backs
/// ends up aliasing with something else, the error is assumed to be handled gracefully.
///
/// As with [`borrow_mutably`] and friends, setting `T` to [`Nothing`] causes this guard to have no
/// effect on the statically-analyzed borrow counts.
///
/// If the error cannot be handled gracefully, one may construct a `MutableBorrow` and
/// [`downgrade`](MutableBorrow::downgrade) it to a `PotentialMutableBorrow` so that the static
/// analyzer will start reporting these potentially aliasing borrows again.
///
/// See the [Potential Borrows](index.html#potential-borrows) section of the crate documentation for
/// more details.
#[repr(transparent)]
pub struct PotentialMutableBorrow<T: ?Sized>(MutableBorrow<T>);
impl<T: ?Sized> PotentialMutableBorrow<T> {
/// Constructs a new `PotentialMutableBorrow` guard.
///
/// This function has no runtime cost but will cause the AuToken static analyzer to increment the
/// number of mutable borrows of type `T` in scope. Note, however, that it will not cause the
/// static analyzer to report aliases with potentially confounding borrow tokens. See the structure
/// documentation for details.
///
/// Internally, this function calls:
///
/// ```rust
/// # use autoken::MutableBorrow;
/// # type T = u32;
/// autoken::assume_no_alias(|| MutableBorrow::<T>::new());
/// ```
pub fn new() -> Self {
assume_no_alias(|| Self(MutableBorrow::new()))
}
/// Creates a loaned [`MutableBorrow`] of this guard which has no effect on the static analysis
/// borrow counters by itself, making it safe to use in conditional code.
///
/// This is typically used to construct the `MutableBorrow` guard for runtime borrow guards which
/// were successfully created in fallible code.
///
/// See the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation for more details on loans.
pub fn loan(&mut self) -> MutableBorrow<Nothing<'_>> {
MutableBorrow::new()
}
/// Creates a loaned `MutableBorrow` of this guard which has no effect on the static analysis
/// borrow counters by itself, making it safe to use in conditional code.
///
/// This is typically used to construct the `MutableBorrow` guard for runtime borrow guards which
/// were successfully created in fallible code.
///
/// Unlike [loan](PotentialMutableBorrow::loan), this method takes an immutable reference to the
/// loaning `PotentialMutableBorrow`, which makes it more prone to accidental borrow aliasing.
///
/// See the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation for more details on loans.
pub fn assume_no_alias_loan(&self) -> MutableBorrow<Nothing<'_>> {
MutableBorrow::new()
}
/// Transforms the type of `T` into [`Nothing`], effectively making it as if this borrow guard no
/// longer exists.
///
/// See the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation for more details on the utility of `strip_lifetime_analysis`.
pub fn strip_lifetime_analysis(self) -> PotentialMutableBorrow<Nothing<'static>> {
drop(self);
PotentialMutableBorrow::new()
}
}
impl<T: ?Sized> Default for PotentialMutableBorrow<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: ?Sized> fmt::Debug for PotentialMutableBorrow<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PotentialMutableBorrow")
.finish_non_exhaustive()
}
}
impl<T: ?Sized> Eq for PotentialMutableBorrow<T> {}
impl<T: ?Sized> PartialEq for PotentialMutableBorrow<T> {
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl<T: ?Sized> Ord for PotentialMutableBorrow<T> {
fn cmp(&self, _other: &Self) -> Ordering {
Ordering::Equal
}
}
impl<T: ?Sized> PartialOrd for PotentialMutableBorrow<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: ?Sized> Clone for PotentialMutableBorrow<T> {
fn clone(&self) -> Self {
Self::new()
}
}
/// A variant of [`ImmutableBorrow`] which represents an immutable borrow which can gracefully recover from
/// borrow errors if they end up occurring.
///
/// Unlike an `ImmutableBorrow`, this token will not trigger a warning if a confounding borrow is
/// potentially alive at the same time as it since, if the dynamic borrow this borrow guard backs
/// ends up aliasing with something else, the error is assumed to be handled gracefully.
///
/// As with [`borrow_immutably`] and friends, setting `T` to [`Nothing`] causes this guard to have no
/// effect on the statically-analyzed borrow counts.
///
/// If the error cannot be handled gracefully, one may construct an `ImmutableBorrow` and
/// [`downgrade`](ImmutableBorrow::downgrade) it to a `PotentialImmutableBorrow` so that the static
/// analyzer will start reporting these potentially aliasing borrows again.
///
/// See the [Potential Borrows](index.html#potential-borrows) section of the crate documentation for
/// more details.
#[repr(transparent)]
pub struct PotentialImmutableBorrow<T: ?Sized>(ImmutableBorrow<T>);
impl<T: ?Sized> PotentialImmutableBorrow<T> {
/// Constructs a new `PotentialImmutableBorrow` guard.
///
/// This function has no runtime cost but will cause the AuToken static analyzer to increment the
/// number of immutable borrows of type `T` in scope. Note, however, that it will not cause the
/// static analyzer to report aliases with potentially confounding borrow tokens. See the structure
/// documentation for details.
///
/// Internally, this function calls:
///
/// ```rust
/// # use autoken::ImmutableBorrow;
/// # type T = u32;
/// autoken::assume_no_alias(|| ImmutableBorrow::<T>::new());
/// ```
pub fn new() -> Self {
assume_no_alias(|| Self(ImmutableBorrow::new()))
}
/// Creates a loaned [`ImmutableBorrow`] of this guard which has no effect on the static analysis
/// borrow counters by itself, making it safe to use in conditional code.
///
/// This is typically used to construct the `ImmutableBorrow` guard for runtime borrow guards which
/// were successfully created in fallible code.
///
/// See the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation for more details on loans.
pub const fn loan(&self) -> ImmutableBorrow<Nothing<'_>> {
ImmutableBorrow::new()
}
/// Transforms the type of `T` into [`Nothing`], effectively making it as if this borrow guard no
/// longer exists.
///
/// See the [Making Sense of Control Flow Errors](index.html#making-sense-of-control-flow-errors)
/// section of the crate documentation for more details on the utility of `strip_lifetime_analysis`.
pub fn strip_lifetime_analysis(self) -> PotentialImmutableBorrow<Nothing<'static>> {
drop(self);
PotentialImmutableBorrow::new()
}
}
impl<T: ?Sized> Default for PotentialImmutableBorrow<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: ?Sized> fmt::Debug for PotentialImmutableBorrow<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PotentialImmutableBorrow")
.finish_non_exhaustive()
}
}
impl<T: ?Sized> Eq for PotentialImmutableBorrow<T> {}
impl<T: ?Sized> PartialEq for PotentialImmutableBorrow<T> {
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl<T: ?Sized> Ord for PotentialImmutableBorrow<T> {
fn cmp(&self, _other: &Self) -> Ordering {
Ordering::Equal
}
}
impl<T: ?Sized> PartialOrd for PotentialImmutableBorrow<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: ?Sized> Clone for PotentialImmutableBorrow<T> {
fn clone(&self) -> Self {
Self::new()
}
}