I have an Rc<Option<T>> but need to get an Rc<T> from it. Something like:
let rc_option: Rc<Option<T>> = Rc::new(Ok(value));
let ok_value: Rc<T> = rc_option.map(|option| option.unwrap());
Is this even remotely possible? It seems like something that should make sense, as the Rc could just increment the counter it has internally for the new mapped value, but I can't find any docs for it.
No, it's not possible to create a Rc<T> from an Rc<Option<T>> that leaves the latter still existing. It is possible to create an Rc<&T> however, from a Rc<Option<T>>, while still leaving the latter variable existing.
If you're trying to create a new Rc<T> that owns the T inside the Rc<Option<T>>, you will have to consume the original Rc<Option<T>>. You also can't have multiple instances of the Rc<Option<T>>, because then you're moving the shared value while pointers still exist, which is very unsafe.
But there is a way to do this safely! Using Rc::try_unwrap, you can attempt to move the value out, but this will return an error if multiple instances of the original Rc exist.
Keep in mind you also have to handle the scenario where Option<T> ends up being None.
Here's an example of this:
let rc_option: Rc<Option<T>> = Rc::new(Some(value));
match Rc::try_unwrap(rc_option) {
Ok(option) => {
match option {
Some(t) => {
let ok_value: Rc<T> = Rc::new(t);
// Do something with ok_value
}
None => {
// Do something else here
}
}
}
Err(rc_option) => {
// There are multiple owners, do something else here
}
}
If you wanted to preserve the original, you could do this:
match &*rc_option {
Some(ref t) => {
let ok_ref: Rc<&T> = Rc::new(t);
}
None => { /* Do something else, there's no internal value */ }
}
EDIT: As Chronial mentioned, do note that the ok_ref cannot outlive rc_option (because it's a reference to rc_option), which may not be what you want to happen.
This is not possible with Rc simply because of its memory layout:
// Equivalence:
struct RcBox<T> {
strong: AtomicUsize,
weak: AtomicUsize,
data: T,
};
struct Rc<T> {
ptr: *const RcBox<T>,
};
Therefore, the counters are expected to be right next to T, and so you cannot share counters between two distinct elements.
From a memory-layout point of view, it is perfectly acceptable to create an alternative FlexRc:
struct Counters {
strong: AtomicUsize,
weak: AtomicUsize, // if support for FlexWeak is desired.
ptr: *mut (),
drop: fn(*mut ()),
}
struct FlexRc<T> {
counters: *mut Counters,
ptr: *const T,
}
And this one could in theory allow mapping... however creating a safe interface over it may not be easy.
How do you prevent the user from returning an unrelated lifetime in map? Is guaranteeing the lifetime of the return reference exceeds that of flex sufficient to be safe?
fn fool(flex: FlexRc<Option<i32>>) -> FlexRc<i32> {
let i = 3;
flex.map(|_| &i)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With