#![warn(rust_2018_idioms, single_use_lifetimes)] use std::pin::Pin; use pin_project::{pin_project, pinned_drop}; #[test] fn safe_project() { #[pin_project(PinnedDrop)] pub struct Struct<'a> { was_dropped: &'a mut bool, #[pin] field: u8, } #[pinned_drop] impl PinnedDrop for Struct<'_> { fn drop(self: Pin<&mut Self>) { **self.project().was_dropped = true; } } let mut was_dropped = false; drop(Struct { was_dropped: &mut was_dropped, field: 42 }); assert!(was_dropped); } #[test] fn self_call() { #[pin_project(PinnedDrop)] pub struct S(T); trait Trait { fn self_ref(&self) {} fn self_pin_ref(self: Pin<&Self>) {} fn self_mut(&mut self) {} fn self_pin_mut(self: Pin<&mut Self>) {} fn assoc_fn(_this: Pin<&mut Self>) {} } impl Trait for S {} #[pinned_drop] impl PinnedDrop for S { fn drop(mut self: Pin<&mut Self>) { self.self_ref(); self.as_ref().self_pin_ref(); self.self_mut(); self.as_mut().self_pin_mut(); Self::assoc_fn(self.as_mut()); ::assoc_fn(self.as_mut()); } } } #[test] fn self_ty() { #[pin_project(PinnedDrop)] pub struct Struct { pub f: (), } #[pinned_drop] impl PinnedDrop for Struct { #[allow(irrefutable_let_patterns)] #[allow(clippy::match_single_binding)] fn drop(mut self: Pin<&mut Self>) { // expr let _: Self = Self { f: () }; // pat match *self { Self { f: () } => {} } if let Self { f: () } = *self {} let Self { f: () } = *self; } } #[pin_project(PinnedDrop)] pub struct TupleStruct(()); #[pinned_drop] impl PinnedDrop for TupleStruct { #[allow(irrefutable_let_patterns)] fn drop(mut self: Pin<&mut Self>) { // expr let _: Self = Self(()); // pat match *self { Self(_) => {} } if let Self(_) = *self {} let Self(_) = *self; } } #[pin_project(PinnedDrop, project = EnumProj, project_ref = EnumProjRef)] pub enum Enum { Struct { f: () }, Tuple(()), Unit, } #[pinned_drop] impl PinnedDrop for Enum { fn drop(mut self: Pin<&mut Self>) { // expr let _: Self = Self::Struct { f: () }; let _: Self = Self::Tuple(()); let _: Self = Self::Unit; // pat match *self { Self::Struct { f: () } => {} Self::Tuple(_) => {} Self::Unit => {} } if let Self::Struct { f: () } = *self {} if let Self::Tuple(_) = *self {} if let Self::Unit = *self {} } } } #[test] fn self_inside_macro_containing_fn() { macro_rules! mac { ($($tt:tt)*) => { $($tt)* }; } #[pin_project(PinnedDrop)] pub struct S(()); #[pinned_drop] impl PinnedDrop for S { fn drop(self: Pin<&mut Self>) { mac!({ impl S { pub fn _f(self) -> Self { self } } }); } } } // See also `ui/pinned_drop/self.rs`. #[rustversion::since(1.40)] // https://github.com/rust-lang/rust/pull/64690 #[test] fn self_inside_macro_def() { #[pin_project(PinnedDrop)] pub struct S(()); #[pinned_drop] impl PinnedDrop for S { fn drop(self: Pin<&mut Self>) { macro_rules! mac { () => {{ let _ = self; let _ = Self(()); }}; } mac!(); } } } #[test] fn self_arg_inside_macro_call() { #[pin_project(PinnedDrop)] struct Struct { f: (), } #[pinned_drop] impl PinnedDrop for Struct { fn drop(self: Pin<&mut Self>) { let _: Vec<_> = vec![self.f]; } } } #[test] fn self_ty_inside_macro_call() { macro_rules! mac { ($($tt:tt)*) => { $($tt)* }; } #[pin_project(PinnedDrop)] pub struct Struct where mac!(Self): Send, { _f: T, } impl Struct { const ASSOC1: usize = 1; fn assoc1() {} } trait Trait { type Assoc2; const ASSOC2: usize; fn assoc2(); } impl Trait for Struct { type Assoc2 = u8; const ASSOC2: usize = 2; fn assoc2() {} } #[pinned_drop] impl PinnedDrop for Struct where mac!(Self): Send, { #[allow(path_statements)] #[allow(clippy::no_effect)] fn drop(self: Pin<&mut Self>) { // inherent items mac!(Self::ASSOC1;); mac!(::ASSOC1;); mac!(Self::assoc1();); mac!(::assoc1();); // trait items mac!(let _: ::Assoc2;); mac!(Self::ASSOC2;); mac!(::ASSOC2;); mac!(::ASSOC2;); mac!(Self::assoc2();); mac!(::assoc2();); mac!(::assoc2();); } } } #[test] fn inside_macro() { #[pin_project(PinnedDrop)] struct S(()); macro_rules! mac { ($expr:expr) => { #[pinned_drop] impl PinnedDrop for S { fn drop(self: Pin<&mut Self>) { let _ = $expr; } } }; } mac!(1); } pub mod self_path { use super::*; #[pin_project(PinnedDrop)] pub struct S(T); fn f() {} #[pinned_drop] impl PinnedDrop for self::S { fn drop(mut self: Pin<&mut Self>) { self::f(); let _: self::S<()> = self::S(()); let _: self::S> = self::S(self.as_mut()); let self::S(()) = self::S(()); let self::S(&mut Self(_)) = self::S(&mut *self); } } }