-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce {Ref, RefMut}::try_map for optional projections in RefCell #78455
Conversation
r? @sfackler (rust_highfive has picked a reviewer for you, use r? to override) |
r? @KodrAus |
This seems like a reasonable addition to me. We could consider a method like fn try_map<F, U, R>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, R::Error>
where
F: FnOnce(&T) -> R,
R: Try<Ok = &U> What do you think? |
Thanks for taking a look. This seems good to me. I'll take it for a spin! |
Updated and seems to work 🎉 |
@udoprog your current implementation is unsound! You cannot name the lifetimes like so: fn try_map<F, U, R>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, R::Error>
where
F: FnOnce(&'b T) -> R,
R: Try<Ok = &'b U> Because this allows you to extract the value out of the Here's one (clunky and really bad) solution that works playground. But it doesn't play with closures well, so you'll need to use functions playground. Or we could not generalize to |
@RustyYato doh, I had a feeling something was gonna go wrong with removing the HRTB's. Thanks for showcasing it! FWIW, returning |
For now I've at least pushed an impl that returns While working on it I noticed that a variant that returns Here it is: udoprog@fc60063#diff-75a679ddd1aae61c8b60e45cea1fb213a086caee3600993c68af9f7a09785e9eR1444 |
You can simplify the match a bit match f(unsafe { &mut *value }) {
Some(value) => Ok(RefMut { value, borrow }),
None => Err(RefMut { value: unsafe { &mut *value }, borrow }),
} But yes, this is sound (exactly because of HRTB 😁) |
Hmm, I don't think I'd want to stabilize |
I'm fine either way. I do prefer one that produces But I'll defer to other people's judgement. Tell me what to do and I'll do it. |
Ah that's an interesting point 🤔 That might be a better way to go then since this is already a niche API. I'm still thinking So what do we think of: pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, Self>
where
F: FnOnce(&T) -> Option<&U>; |
The job Click to see the possible cause of the failure (guessed by this bot)
|
The job Click to see the possible cause of the failure (guessed by this bot)
|
The job Click to see the possible cause of the failure (guessed by this bot)
|
The use of Result allows for making use of a reconstructed original value on failed projections.
Using |
📌 Commit c625b97 has been approved by |
Introduce {Ref, RefMut}::try_map for optional projections in RefCell This fills a usability gap of `RefCell` I've personally encountered to perform optional projections, mostly into collections such as `RefCell<Vec<T>>` or `RefCell<HashMap<U, T>>`: > This kind of API was briefly featured under Open questions in rust-lang#10514 back in 2013 (!) ```rust let values = RefCell::new(vec![1, 2, 3, 4]); let b = Ref::opt_map(values.borrow(), |vec| vec.get(2)); ``` It primarily avoids this alternative approach to accomplish the same kind of projection which is both rather noisy and panicky: ```rust let values = RefCell::new(vec![1, 2, 3, 4]); let b = if values.get(2).is_some() { Some(Ref::map(values.borrow(), |vec| vec.get(2).unwrap())) } else { None }; ``` ### Open questions The naming `opt_map` is preliminary. I'm not aware of prior art in std to lean on here, but this name should probably be improved if this functionality is desirable. Since `opt_map` consumes the guard, and alternative syntax might be more appropriate which instead *tries* to perform the projection, allowing the original borrow to be recovered in case it fails: ```rust pub fn try_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, Self> where F: FnOnce(&T) -> Option<&U>; ``` This would be more in line with the `try_map` method [provided by parking lot](https://docs.rs/lock_api/0/lock_api/struct.RwLockWriteGuard.html#method.try_map).
Introduce {Ref, RefMut}::try_map for optional projections in RefCell This fills a usability gap of `RefCell` I've personally encountered to perform optional projections, mostly into collections such as `RefCell<Vec<T>>` or `RefCell<HashMap<U, T>>`: > This kind of API was briefly featured under Open questions in rust-lang#10514 back in 2013 (!) ```rust let values = RefCell::new(vec![1, 2, 3, 4]); let b = Ref::opt_map(values.borrow(), |vec| vec.get(2)); ``` It primarily avoids this alternative approach to accomplish the same kind of projection which is both rather noisy and panicky: ```rust let values = RefCell::new(vec![1, 2, 3, 4]); let b = if values.get(2).is_some() { Some(Ref::map(values.borrow(), |vec| vec.get(2).unwrap())) } else { None }; ``` ### Open questions The naming `opt_map` is preliminary. I'm not aware of prior art in std to lean on here, but this name should probably be improved if this functionality is desirable. Since `opt_map` consumes the guard, and alternative syntax might be more appropriate which instead *tries* to perform the projection, allowing the original borrow to be recovered in case it fails: ```rust pub fn try_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, Self> where F: FnOnce(&T) -> Option<&U>; ``` This would be more in line with the `try_map` method [provided by parking lot](https://docs.rs/lock_api/0/lock_api/struct.RwLockWriteGuard.html#method.try_map).
Rollup of 17 pull requests Successful merges: - rust-lang#78455 (Introduce {Ref, RefMut}::try_map for optional projections in RefCell) - rust-lang#80144 (Remove giant badge in README) - rust-lang#80614 (Explain why borrows can't be held across yield point in async blocks) - rust-lang#80670 (TrustedRandomAaccess specialization composes incorrectly for nested iter::Zips) - rust-lang#80681 (Clarify what the effects of a 'logic error' are) - rust-lang#80764 (Re-stabilize Weak::as_ptr and friends for unsized T) - rust-lang#80901 (Make `x.py --color always` apply to logging too) - rust-lang#80902 (Add a regression test for rust-lang#76281) - rust-lang#80941 (Do not suggest invalid code in pattern with loop) - rust-lang#80968 (Stabilize the poll_map feature) - rust-lang#80971 (Put all feature gate tests under `feature-gates/`) - rust-lang#81021 (Remove doctree::Import) - rust-lang#81040 (doctest: Reset errors before dropping the parse session) - rust-lang#81060 (Add a regression test for rust-lang#50041) - rust-lang#81065 (codegen_cranelift: Fix redundant semicolon warn) - rust-lang#81069 (Add sample code for Rc::new_cyclic) - rust-lang#81081 (Add test for rust-lang#34792) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
With a return type like that, I think it makes sense to do this in a way that doesn't use So 👍 to phrasing this as filter_map and just supporting |
This fills a usability gap of
RefCell
I've personally encountered to perform optional projections, mostly into collections such asRefCell<Vec<T>>
orRefCell<HashMap<U, T>>
:It primarily avoids this alternative approach to accomplish the same kind of projection which is both rather noisy and panicky:
Open questions
The naming
opt_map
is preliminary. I'm not aware of prior art in std to lean on here, but this name should probably be improved if this functionality is desirable.Since
opt_map
consumes the guard, and alternative syntax might be more appropriate which instead tries to perform the projection, allowing the original borrow to be recovered in case it fails:This would be more in line with the
try_map
method provided by parking lot.