Skip to content
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

Tracking issue for cell_extras stabilization #27746

Closed
aturon opened this issue Aug 12, 2015 · 19 comments
Closed

Tracking issue for cell_extras stabilization #27746

aturon opened this issue Aug 12, 2015 · 19 comments
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@aturon
Copy link
Member

aturon commented Aug 12, 2015

The Ref type connected to RefCell supports some methods for changing the type of the reference, such as map and filter_map. While map is clearly fully general, filter_map is somewhat of a special case hooked into Option. To make it fully general would likely require HKT. We need an overall plan before stabilization.

@aturon aturon added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. B-unstable Blocker: Implemented in the nightly compiler and unstable. labels Aug 12, 2015
@aturon
Copy link
Member Author

aturon commented Aug 12, 2015

cc @SimonSapin

@SimonSapin
Copy link
Contributor

This is the kind of thing (unlike say ref_slice #27774) that is impossible to do reasonably outside of std. (Where “unreasonable” is guessing struct layout to access private fields.)

@SimonSapin
Copy link
Contributor

(Ok, thinking a bit more about it, this may not be true. Something like https://github.com/Kimundi/owning-ref-rs/ could, using (Ref<'a, T>, *const U) and unsafe code to dereference the raw pointer, have equivalent functionality with a different API (separate type) and 3 words instead of 2 per reference.)

@mbrt
Copy link

mbrt commented Dec 8, 2015

What about making RefCell::map stable? It has good use cases and it is clearly usable as-is.

@SimonSapin
Copy link
Contributor

I’d like to nominate at least Ref::map and RefMut::map for stabilization.

filter_map’s functionality can be safely built on top of it with a performance cost (testing the presence of the mapped thing twice). For example:

fn borrow_get<'a>(hashmap: &'a RefCell<HashMap<String, String>>, key: &str) 
                  -> Option<Ref<'a String>> {
    let hashmap: = hashmap.borrow();
    if hashmap:.contains_key(key) {  // Duplicated hash table lookup.
        Some(Ref::map(|hashmap| {
            hashmap[key]  // panic!() for missing key unlikely to be optimized away
        }))
    } else {
        None
    }
}

It’s probably possible to do it unsafely without the run-time cost with raw pointers. (But still less risky than guessing the memory layout of Ref or RefMut.)

@SimonSapin
Copy link
Contributor

For future reference, here is fully generic filter_map built on top of map using raw pointers. I’m fairly confident that it’s safe.

use std::cell::{Ref, RefMut};

pub fn ref_filter_map<
    T: ?Sized,
    U: ?Sized,
    F: FnOnce(&T) -> Option<&U>
>(orig: Ref<T>, f: F) -> Option<Ref<U>> {
    f(&orig)
        .map(|new| new as *const U)
        .map(|raw| Ref::map(orig, |_| unsafe { &*raw }))
}

pub fn ref_mut_filter_map<
    T: ?Sized,
    U: ?Sized,
    F: FnOnce(&mut T) -> Option<&mut U>
>(mut orig: RefMut<T>, f: F) -> Option<RefMut<U>> {
    f(&mut orig)
        .map(|new| new as *mut U)
        .map(|raw| RefMut::map(orig, |_| unsafe { &mut *raw }))
}

@alexcrichton
Copy link
Member

🔔 This issue is now entering its cycle final comment period to be handled in 1.8 🔔

We're specifically considering stabilizing map and deprecating filter_map. We're also willing to stabilize map on the lock-related guards as well so long as they land soon.

@alexcrichton alexcrichton added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed I-nominated labels Jan 29, 2016
@reem
Copy link
Contributor

reem commented Feb 5, 2016

As just noted in #30834:

I've discovered a safety hole in MutexGuard::map - it is not safe in combination with Condvar, since the "inner" borrow can be invalidated by another thread taking the lock during a Condvar::wait see: http://is.gd/RM038X.

This is not a problem with the RwLock guard methods, since the RwLock guards cannot be used with a Condvar.

It would be possible to provide a similar, but safe, API by defining a separate type for "mapped" mutex guards that can't be used with a Condvar.

reem added a commit to reem/rust that referenced this issue Feb 5, 2016
It could return in the future if it returned a different guard type, which
could not be used with Condvar, otherwise it is unsafe as another thread
can invalidate an "inner" reference during a Condvar::wait.

cc rust-lang#27746
@alexcrichton
Copy link
Member

With MutexGuard::map being removed in #31428, we may wish to also remove the RwLock*Guard::map functions even though they're not used with CondVar at this time. Windows actually has the ability to wait on condvars with rwlocks via SleepConditionVariableSRW, which we also use internally. That seems like it would be a viable platform-specific extension, and perhaps even an extension we could support via other trickery. (I think C++ has something like condition_variable_any?)

@aturon
Copy link
Member Author

aturon commented Feb 5, 2016

@alexcrichton Certainly we shouldn't stabilize them, and I tend to agree that we should probably remove them and do this in a more considered way.

@ghost
Copy link

ghost commented Feb 5, 2016

If you decide to keep these functions (or at least the one on RwLock I guess), the lifetimes should be removed from the closure like in Ref::map, or at least not made the same as the underlying container. By using the same lifetime as the container, the reference can escape from the closure. See: #25747 (comment)

http://is.gd/vUbM4D (the example in the link above modified for RwLock currently results in use-after-free).
http://is.gd/f0AtWL (using a function with the signature changed fails to compile)

@reem
Copy link
Contributor

reem commented Feb 6, 2016

I need a RwLock that can be waited on for other reasons, so I implemented an equivalent to C++17s std::shared_mutex which is a fair reader-writer lock implemented using a mutex and two condvars.

I went ahead and also demoed a (I believe) safe API for map/option_map/result_map in the same crate based on having a different type for mappable and waitable guards. I think we could apply the same strategy to both RwLock and Mutex in std.

Code: https://github.com/reem/rust-shared-mutex
Mappable Guards: https://github.com/reem/rust-shared-mutex/blob/6dca082c864df3d46fa952ff89f7c813aa7b2012/src/lib.rs#L379-L504

EDIT: Also submitted #31440 to fix the safety hole noted by @whataloadofwhat and update the unstable reason to include a note about a possible bad interaction with Condvar.

bors added a commit that referenced this issue Feb 6, 2016
It could return in the future if it returned a different guard type, which
could not be used with Condvar, otherwise it is unsafe as another thread
can invalidate an "inner" reference during a Condvar::wait.

cc #27746
@alexcrichton
Copy link
Member

The libs team discussed this during triage yesterday and the decision was to:

  • Stabilize Ref::map and RefMut::map
  • Deprecate everything else (if it still exists), including filter_map

alexcrichton added a commit to alexcrichton/rust that referenced this issue Feb 29, 2016
This commit is the result of the FCPs ending for the 1.8 release cycle for both
the libs and the lang suteams. The full list of changes are:

Stabilized

* `braced_empty_structs`
* `augmented_assignments`
* `str::encode_utf16` - renamed from `utf16_units`
* `str::EncodeUtf16` - renamed from `Utf16Units`
* `Ref::map`
* `RefMut::map`
* `ptr::drop_in_place`
* `time::Instant`
* `time::SystemTime`
* `{Instant,SystemTime}::now`
* `{Instant,SystemTime}::duration_since` - renamed from `duration_from_earlier`
* `{Instant,SystemTime}::elapsed`
* Various `Add`/`Sub` impls for `Time` and `SystemTime`
* `SystemTimeError`
* `SystemTimeError::duration`
* Various impls for `SystemTimeError`
* `UNIX_EPOCH`
* `ops::{Add,Sub,Mul,Div,Rem,BitAnd,BitOr,BitXor,Shl,Shr}Assign`

Deprecated

* Scoped TLS (the `scoped_thread_local!` macro)
* `Ref::filter_map`
* `RefMut::filter_map`
* `RwLockReadGuard::map`
* `RwLockWriteGuard::map`
* `Condvar::wait_timeout_with`

Closes rust-lang#27714
Closes rust-lang#27715
Closes rust-lang#27746
Closes rust-lang#27748
Closes rust-lang#27908
Closes rust-lang#29866
bors added a commit that referenced this issue Feb 29, 2016
This commit is the result of the FCPs ending for the 1.8 release cycle for both
the libs and the lang suteams. The full list of changes are:

Stabilized

* `braced_empty_structs`
* `augmented_assignments`
* `str::encode_utf16` - renamed from `utf16_units`
* `str::EncodeUtf16` - renamed from `Utf16Units`
* `Ref::map`
* `RefMut::map`
* `ptr::drop_in_place`
* `time::Instant`
* `time::SystemTime`
* `{Instant,SystemTime}::now`
* `{Instant,SystemTime}::duration_since` - renamed from `duration_from_earlier`
* `{Instant,SystemTime}::elapsed`
* Various `Add`/`Sub` impls for `Time` and `SystemTime`
* `SystemTimeError`
* `SystemTimeError::duration`
* Various impls for `SystemTimeError`
* `UNIX_EPOCH`
* `ops::{Add,Sub,Mul,Div,Rem,BitAnd,BitOr,BitXor,Shl,Shr}Assign`

Deprecated

* Scoped TLS (the `scoped_thread_local!` macro)
* `Ref::filter_map`
* `RefMut::filter_map`
* `RwLockReadGuard::map`
* `RwLockWriteGuard::map`
* `Condvar::wait_timeout_with`

Closes #27714
Closes #27715
Closes #27746
Closes #27748
Closes #27908
Closes #29866
Closes #28235
Closes #29720
@alexcrichton
Copy link
Member

Reopening as apparently Ref::clone is still under this umbrella.

@alexcrichton alexcrichton reopened this May 26, 2016
@alexcrichton
Copy link
Member

Also cc #33880, possible unsoundness with that method.

@alexcrichton alexcrichton removed the final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. label Jun 9, 2016
@alexcrichton
Copy link
Member

@rfcbot fcp merge

Sounds like Ref::clone is ready for stabilizing

@rfcbot
Copy link

rfcbot commented Nov 1, 2016

Team member @alexcrichton has proposed to merge this. The next step is review by the rest of the tagged teams:

No concerns currently listed.

Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot
Copy link

rfcbot commented Nov 12, 2016

🔔 This is now entering its final comment period, as per the review above. 🔔

psst @alexcrichton, I wasn't able to add the final-comment-period label, please do so.

@alexcrichton alexcrichton added the final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. label Nov 12, 2016
@rfcbot
Copy link

rfcbot commented Nov 22, 2016

The final comment period is now complete.

bors added a commit that referenced this issue Dec 18, 2016
Library stabilizations/deprecations for 1.15 release

Stabilized:

- `std::iter::Iterator::{min_by, max_by}`
- `std::os::*::fs::FileExt`
- `std::sync::atomic::Atomic*::{get_mut, into_inner}`
- `std::vec::IntoIter::{as_slice, as_mut_slice}`
- `std::sync::mpsc::Receiver::try_iter`
- `std::os::unix::process::CommandExt::before_exec`
- `std::rc::Rc::{strong_count, weak_count}`
- `std::sync::Arc::{strong_count, weak_count}`
- `std::char::{encode_utf8, encode_utf16}`
- `std::cell::Ref::clone`
- `std::io::Take::into_inner`

Deprecated:

- `std::rc::Rc::{would_unwrap, is_unique}`
- `std::cell::RefCell::borrow_state`

Closes #23755
Closes #27733
Closes #27746
Closes #27784
Closes #28356
Closes #31398
Closes #34931
Closes #35601
Closes #35603
Closes #35918
Closes #36105
dlrobertson pushed a commit to dlrobertson/rust that referenced this issue Nov 29, 2018
This commit is the result of the FCPs ending for the 1.8 release cycle for both
the libs and the lang suteams. The full list of changes are:

Stabilized

* `braced_empty_structs`
* `augmented_assignments`
* `str::encode_utf16` - renamed from `utf16_units`
* `str::EncodeUtf16` - renamed from `Utf16Units`
* `Ref::map`
* `RefMut::map`
* `ptr::drop_in_place`
* `time::Instant`
* `time::SystemTime`
* `{Instant,SystemTime}::now`
* `{Instant,SystemTime}::duration_since` - renamed from `duration_from_earlier`
* `{Instant,SystemTime}::elapsed`
* Various `Add`/`Sub` impls for `Time` and `SystemTime`
* `SystemTimeError`
* `SystemTimeError::duration`
* Various impls for `SystemTimeError`
* `UNIX_EPOCH`
* `ops::{Add,Sub,Mul,Div,Rem,BitAnd,BitOr,BitXor,Shl,Shr}Assign`

Deprecated

* Scoped TLS (the `scoped_thread_local!` macro)
* `Ref::filter_map`
* `RefMut::filter_map`
* `RwLockReadGuard::map`
* `RwLockWriteGuard::map`
* `Condvar::wait_timeout_with`

Closes rust-lang#27714
Closes rust-lang#27715
Closes rust-lang#27746
Closes rust-lang#27748
Closes rust-lang#27908
Closes rust-lang#29866
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants