Skip to content

Commit 62a297e

Browse files
committed
Document the project_replace() method.
1 parent 1db85fa commit 62a297e

File tree

2 files changed

+69
-6
lines changed

2 files changed

+69
-6
lines changed

pin-project-internal/src/lib.rs

+58
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,63 @@ use utils::{Immutable, Mutable, Owned};
226226
///
227227
/// See also [`pinned_drop`] attribute.
228228
///
229+
/// ### `project_replace()`
230+
///
231+
/// In addition to the `project()` and `project_ref()` methods which are always
232+
/// provided when you use the `#[pin_project]` attribute, there is a third method,
233+
/// `project_replace()` which can be useful in some situations. It is equivalent
234+
/// to [`Pin::set`], except that the unpinned fields are moved and returned,
235+
/// instead of being dropped in-place.
236+
///
237+
/// ```
238+
/// # #[rustversion::since(1.36)]
239+
/// # fn dox() {
240+
/// # use std::pin::Pin;
241+
/// # type ProjectionOwned = ();
242+
/// # trait Dox {
243+
/// fn project_replace(self: Pin<&mut Self>, other: Self) -> ProjectionOwned;
244+
/// # }
245+
/// # }
246+
/// ```
247+
///
248+
/// The `ProjectionOwned` type is identical to the `Self` type, except that
249+
/// all pinned fields have been replaced by equivalent `PhantomData` types.
250+
///
251+
/// This method is opt-in, because it is only supported for `Sized` types, and
252+
/// because it is incompatible with the `#[pinned_drop]` attribute described
253+
/// above. It can be enabled by using `#[pin_project(Replace)]`.
254+
///
255+
/// For example:
256+
///
257+
/// ```rust
258+
/// use pin_project::{pin_project, project_replace};
259+
///
260+
/// #[pin_project(Replace)]
261+
/// pub enum Foo<T> {
262+
/// A {
263+
/// #[pin]
264+
/// pinned_field: i32,
265+
/// unpinned_field: T,
266+
/// },
267+
/// B,
268+
/// }
269+
///
270+
/// #[project_replace]
271+
/// fn main() {
272+
/// let mut x = Box::pin(Foo::A { pinned_field: 42, unpinned_field: "hello" });
273+
///
274+
/// #[project_replace]
275+
/// match x.as_mut().project_replace(Foo::B) {
276+
/// Foo::A { unpinned_field, .. } => assert_eq!(unpinned_field, "hello"),
277+
/// Foo::B => unreachable!(),
278+
/// }
279+
/// }
280+
/// ```
281+
///
282+
/// The [`project_replace`] attributes are necessary whenever destructuring the return
283+
/// type of `project_replace()`, and work in exactly the same way as the
284+
/// [`project`] and [`project_ref`] attributes.
285+
///
229286
/// ## Supported Items
230287
///
231288
/// The current pin-project supports the following types of items.
@@ -320,6 +377,7 @@ use utils::{Immutable, Mutable, Owned};
320377
/// [`UnsafeUnpin`]: https://docs.rs/pin-project/0.4/pin_project/trait.UnsafeUnpin.html
321378
/// [`project`]: ./attr.project.html
322379
/// [`project_ref`]: ./attr.project_ref.html
380+
/// [`project_replace`]: ./attr.project_replace.html
323381
/// [`pinned_drop`]: ./attr.pinned_drop.html
324382
#[proc_macro_attribute]
325383
pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream {

pin-project-internal/src/pin_project/derive.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ impl<'a> Context<'a> {
398398
proj_items.extend(quote_spanned! { replace =>
399399
#[allow(dead_code)] // This lint warns unused fields/variants.
400400
#vis struct #proj_own_ident #orig_generics #where_clause_own_fields
401-
})
401+
});
402402
}
403403

404404
let proj_mut_body = quote! {
@@ -453,7 +453,7 @@ impl<'a> Context<'a> {
453453
let proj_generics = &self.proj.generics;
454454
let where_clause = &self.proj.where_clause;
455455

456-
let proj_items = quote! {
456+
let mut proj_items = quote! {
457457
#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
458458
#[allow(dead_code)] // This lint warns unused fields/variants.
459459
#vis enum #proj_ident #proj_generics #where_clause {
@@ -463,12 +463,17 @@ impl<'a> Context<'a> {
463463
#vis enum #proj_ref_ident #proj_generics #where_clause {
464464
#proj_ref_variants
465465
}
466-
#[allow(dead_code)] // This lint warns unused fields/variants.
467-
#vis enum #proj_own_ident #orig_generics #orig_where_clause {
468-
#proj_own_variants
469-
}
470466
};
471467

468+
if let Some(replace) = self.replace {
469+
proj_items.extend(quote_spanned! { replace =>
470+
#[allow(dead_code)] // This lint warns unused fields/variants.
471+
#vis enum #proj_own_ident #orig_generics #orig_where_clause {
472+
#proj_own_variants
473+
}
474+
});
475+
}
476+
472477
let proj_mut_body = quote! {
473478
match self.get_unchecked_mut() {
474479
#proj_arms

0 commit comments

Comments
 (0)