Skip to content

Tracking Issue for smart pointer (try_)map #144419

Open

Description

@Qelxiros

Feature gate: #![feature(smart_pointer_try_map)]

This is a tracking issue for map and try_map functions for various smart pointer types, as per rust-lang/libs-team#364

Public API

// Taking T by value
impl Box<T> {
    fn map<U>(this: Self, f: impl FnOnce(T) -> U) -> Box<U>;
    fn try_map<R>(this: Self, f: impl FnOnce(T) -> R) -> ChangeOutputType<R, Box<R::Output>>
    where
        R: Try,
        R::Residual: Residual<Box<R::Output, A>>;
}
impl UniqueRc<T> {
    fn map<U>(this: Self, f: impl FnOnce(T) -> U) -> UniqueRc<U>;
    fn try_map<R>(this: Self, f: impl FnOnce(T) -> R) -> ChangeOutputType<R, UniqueRc<R::Output>>
    where
        R: Try,
        R::Residual: Residual<UniqueRc<R::Output, A>>;
}
impl UniqueArc<T> {
    fn map<U>(this: Self, f: impl FnOnce(T) -> U) -> UniqueArc<U>;
    fn try_map<R>(this: Self, f: impl FnOnce(T) -> R) -> ChangeOutputType<R, UniqueArc<R::Output>>
    where
        R: Try,
        R::Residual: Residual<UniqueArc<R::Output, A>>;
}

// Taking T by reference
impl Rc<T> {
    fn map<U>(this: Self, f: impl FnOnce(&T) -> U) -> Rc<U>;
    fn try_map<R>(this: Self, f: impl FnOnce(&T) -> R) -> ChangeOutputType<R, Rc<R::Output>>
    where
        R: Try,
        R::Residual: Residual<Rc<R::Output, A>>;
}
impl Arc<T> {
    fn map<U>(this: Self, f: impl FnOnce(&T) -> U) -> Arc<<U>;
    fn try_map<R>(this: Self, f: impl FnOnce(&T) -> R) -> ChangeOutputType<R, Arc<<R::Output>>
    where
        R: Try,
        R::Residual: Residual<Arc<R::Output, A>>;
}

Steps / History

(Remember to update the S-tracking-* label when checking boxes.)

Unresolved Questions

Footnotes

  1. https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html ↩

Activity

  1. added
    T-libs-api[DEPRECATED; DO NOT USE]
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    on Jul 24, 2025
  2. tmke8 commented on Sep 21, 2025

    @tmke8

    I see in the linked PR that if size or alignment of the input and output type don't match, then it falls back to Box::new(f(*this)). This sort of makes sense but it kind of defeats the purpose of the function. What about returning a compiler error instead, if size or alignment don't match?

  3. added a commit that references this issue on Oct 31, 2025
  4. added a commit that references this issue on Oct 31, 2025
  5. orlp commented on Nov 5, 2025

    @orlp
    Contributor

    @tmke8 That makes the function unusable in generic code (e.g. Box<T> -> Box<T::Foo> where T: HasFoo), big downvote from me.

  6. added 2 commits that reference this issue on Nov 8, 2025
  7. tmke8 commented on Nov 11, 2025

    @tmke8

    Well, I was imagining that the compiler error would be thrown on monomorphization, in which case your code would work fine, I think. But I have to admit I'm not an expert on where compiler errors can be raised.

    EDIT: sorry, "static assert" is a much better term for what I was imagining than "compiler error"

    EDIT2: e.g., using something like this: https://docs.rs/static_assertions/latest/static_assertions/macro.assert_eq_align.html

  8. 23 remaining items

  9. added 6 commits that reference this issue on Sep 1, 2026
  10. added a commit that references this issue on Sep 1, 2026
  11. sugar700 commented on Sep 3, 2026

    @sugar700
    Contributor

    I find this API to be a bit surprising, I would rather expect Arc's map method to work more like MappedMutexGuard.

    use std::ops::Deref;
    use std::ptr::NonNull;
    use std::sync::Arc;
    
    struct MappedArc<T, U> {
        _arc: Arc<T>,
        ptr: NonNull<U>,
    }
    
    impl<T, U> MappedArc<T, U> {
        fn new(arc: Arc<T>, callback: impl FnOnce(&T) -> &U) -> Self {
            let ptr = NonNull::from_ref(callback(&arc));
            Self { _arc: arc, ptr }
        }
    }
    
    impl<T, U> Deref for MappedArc<T, U> {
        type Target = U;
        fn deref(&self) -> &U {
            // safe because Arc still exists (it's owned by MappedArc)
            unsafe { self.ptr.as_ref() }
        }
    }
    
    fn main() {
        let arc = Arc::new((2, 3, 4));
        let mapped = MappedArc::new(arc, |x| &x.1);
        println!("{:?}", *mapped);
    }

    Something like could be pretty useful especially for async code, due to the fact that async code tends to be Arc heavy.

  12. camsteffen commented on Sep 4, 2026

    @camsteffen
    Contributor

    I think the docs could be clearer about the conditions for reusing the allocation. I wasn't sure if it would reuse the allocation if the mapped value is smaller.

  13. nia-e commented on Sep 4, 2026

    @nia-e
    Member

    I'd avoid guaranteeing it regardless - at best we could make it a grow/shrink call, but promising reuse of the allocation would require us to track the original layout used to make the allocation

  14. orlp commented on Sep 4, 2026

    @orlp
    Contributor

    I think it's harmless to guarantee it when T's size and alignment match that of U (which is also the only time we do it currently).

  15. nia-e commented on Sep 5, 2026

    @nia-e
    Member

    That's probably fair. Some part of me is scared that it'll turn out to be weird for some reason I've yet to think of but I'd be okay +1'ing that (will need fcp)

  16. added
    S-tracking-blockedStatus: This tracking issue is blocked on another tracking issue
    and removed on Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCS-tracking-blockedStatus: This tracking issue is blocked on another tracking issueT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions