Skip to content

Mapping Ref to a value containing a reference #54776

@d-e-s-o

Description

@d-e-s-o

Consider the following specific use case explaining a more general
issue: We have a struct, RefStrings, that keeps a RefCell containing
some form of collection, Vec<String>. Part of RefStrings's API
surface is a function that aims to expose an iterator over the
underlying collection. The only possibility I see for exposing the
iterator (conceptually) is via a Ref and using RefCell's map
function:

struct RefStrings(RefCell<Vec<String>>);

impl RefStrings {
    fn iter<'t, 's: 't>(&'s self) -> Ref<'t, Iter<String>> {
        Ref::map(self.0.borrow(), |x| x.iter())
    }
}

(playground)

Unfortunately, that does not work. The reason being that Ref is
defined to hold a reference to a member of the borrowed object, but an
iterator is effectively an actual object in itself that just happens to
have such a reference.

I have not found a way to get this working using the existing
functionality. Am I just missing something?

A possible solution that I worked with now is the introduction of a new
associated function Ref::map_val that returns an object that
effectively contains another object (i.e., something that is Sized)
that may hold a reference to the borrowed data (e.g., a concrete
iterator type). That solves the problem reasonably nicely, in my
opinion.

struct RefStrings(RefCell<Vec<String>>);

impl RefStrings {
    fn iter<'t, 's: 't>(&'s self) -> RefVal<'t, Iter<String>> {
        Ref::map_val(self.0.borrow(), |x| x.iter())
    }
}

// ...
// RefVal is defined as:
pub struct RefVal<'b, T> {
    value: T,
    borrow: BorrowRef<'b>,
}

(see the cell crate for the full functionality; note that the API provided is still limited, i.e., I mostly implemented what I needed right away)

Unfortunately I have not found a way to provide said functionality as
anything else than a replacement of RefCell itself, with all the code
duplication that accompanies.

So, I am filing this issue to discuss

  1. whether I am just missing something and there is a trivial way to
    accomplish what I hopefully explained well enough
  2. if that is not the case, whether this functionality is desired to be
    included in the Rust standard library (I believe this is a general
    problem with a general solution; despite probably not being a very
    common one)
  3. if such a desire exists, the steps to be taken to include this
    functionality (RFC process?)

EDIT: Proposed solution turned out to be unsafe with no known workaround. So really this issue is only to discuss other solutions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-feature-requestCategory: A feature request, i.e: not implemented / a PR.T-libs-apiRelevant to the library API 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