Next Steps Why doesn't Weak :: new () work when Rc :: downgrade () does?
When I try to implement Weak::new() in such a way that it would NOT be required that it allocate memory for the base type, even if it will never be used, I ended up in a checkpoint.
The definition of RcBox<T> quite simple:
struct RcBox<T: ?Sized> { strong: Cell<usize>, weak: Cell<usize>, value: T, }
And the goal here is to create an RcBox<T> that does NOT actually contain value . Essentially RcBox<()> .
However, there is a clue. *mut RcBox<()> is a thin pointer, but *mut RcBox<T> is a potentially thick pointer. We have some data from this fat pointer, but there are many different cases of fat pointers, so trying to synthesize the rest is tough .
As you can see from the related question, I can make it work only for objects with objects:
impl<T: ?Sized> Weak<T> { pub fn new() -> Weak<T> { unsafe { let boxed = Box::into_raw(box RcBox { strong: Cell::new(0), weak: Cell::new(1), value: (), }); let ptr = if size_of::<*mut ()>() == size_of::<*mut T>() { let ptr: *mut RcBox<T> = transmute_copy(&boxed); ptr } else { let ptr: *mut RcBox<T> = transmute_copy(&TraitObject { data: boxed as *mut (), vtable: null_mut(), }); ptr }; Weak { ptr: Shared::new(ptr) } } } }
However, this will not work with str (for example).
I tried to isolate the fixed-size RcBox part, allowing the compiler to output the bold part of the pointer:
struct RcBox<T: ?Sized> { counters: RcBoxCounters<T>, value: T, } struct RcBoxCounters<T: ?Sized> { strong: Cell<usize>, weak: Cell<usize>, _phantom: PhantomData<T>, } impl<T: ?Sized> Weak<T> { pub fn new() -> Weak<T> { unsafe { let boxed = Box::into_raw(box RcBox::Counters::new(0, 1)); Weak { ptr: Shared::new(boxed as *mut RcBox<T>) } } } }
which sounds very smart until the compiler suppresses your enthusiasm:
error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions --> <anon>:58:40 | 58 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<RcBox<U>> for RcBox<T> {} | ^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions | = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced = note: currently, 2 fields need coercions: counters (RcBoxCounters<T> to RcBoxCounters<U>), value (T to U)
I.e:
- I think that in order for the compiler to synthesize the bold part, I need
PhantomData in RcBoxCounters , - however, this requires 2 transformations for coercion, which is not allowed.
So, is there a way to fix Weak::new() so that it does not allocate extraneous (unnecessary) memory?
Note. I mean allocating only space for two counters, after which allocating large and trimming DOES NOT help.
Note. It was noted that to indicate the absence of a value, you can use Option or a special value. This requires branching for each method, which may be undesirable. I prefer to learn to play with bold pointers.