let the_rc: Rc<u32> = todo!();
let p = the_rc.as_ptr();
unsafe fn clone_from<T>(p:*const T) -> Rc<T> {
todo!()
}
Note the above deliberately uses .as_ptr() and notinto_raw() since the pointer is in reality put into a Copy struct and I can not keep track of the number of copies being made. Hence into_raw would end up with a bungled strong count. The unsafe precondition of clone_from is that the Rc is still alive. I do not take a &Rc<T> because the original Rc needs to be movable after the pointer has been derived.
I'm not so sure if the following would be a valid implementation of clone_from:
This seems to do all the right things: we first pretend we cloned the Rc, so the original derivation of the pointer "was" the_rc.clone().into_raw() and then turn it into an Rc. As I said, I can't do that directly because I do not know a prior how many calls to clone_from will be made per pointer, so the ref count can not be fixed at the time of derivation of p.
I think you are misunderstanding the ownership model.
the only difference between as_ptr() and into_raw() is whether the original Rc is forgot, otherwise, they are exactly the same, it's the same type after all, how can you tell a raw pointer is obtained by as_ptr() or into_raw()?
this is a correct implementation in its own. the caller needs to hold the safety invariant, see increment_strong_count().
This is, of course, not true. They're different functions, and the docs for from_raw() and increment_strong_count() do not allow you to call them. So you are not allowed to.
For all you know, the Rc could hold a flag for whether it was obtained via as_ptr() and call unreachable_unchecked() if yes (this is a contrived example of course, to demonstrate the idea).
Yes I noticed that. Then I suppose a better implementation would be
let p = the_rc.clone().into_raw();
Rc::decrement_strong_count(p);
unsafe fn clone_from<T>(p:*const T) -> Rc<T> { /* as in the question */ }
Now the pointer does come from a call into_raw() and I don't see anything about that pointer becoming invalid to pass to from_raw as long as the overall ref count doesn't drop to 0 (technically I don't even see that mentioned, but it does make sense), or the pointer being only usable once for that call.
I mean I suppose that is alright for Rc and fine for me. For Arc, I would be really bugged by the two additional atomic writes to the refcount with the alternative.
Pretty easy to stuff that flag in on arm64 platforms with Top Byte Ignore, with an extra field in the Rc metadata to recover the correct TBI flag given by the allocator