title: Is there a way to prevent Weak::new() from over allocating?
body: <p><em>Follow-up of <a href="https://stackoverflow.com/questions/44573591/why-doesnt-weaknew-work-when-rcdowngrade-does/44574351#44574351">Why doesn&#39;t Weak::new() work when Rc::downgrade() does?</a></em></p>
  
  <p>When attempting to implement <code>Weak::new()</code> in a way that would NOT require it to allocate memory for the underlying type even though it is never going to be used, I hit a roadblock.</p>
  
  <p>The definition of <code>RcBox&lt;T&gt;</code> is rather simple:</p>
  
  <pre><code>struct RcBox&lt;T: ?Sized&gt; {
      strong: Cell&lt;usize&gt;,
      weak: Cell&lt;usize&gt;,
      value: T,
  }
  </code></pre>
  
  <p>And the goal here is to create a <code>RcBox&lt;T&gt;</code> which will actually NOT contain any <code>value</code>. Essentially, a <code>RcBox&lt;()&gt;</code>.</p>
  
  <p>However, there is a snag. <code>*mut RcBox&lt;()&gt;</code> is a thin pointer but <code>*mut RcBox&lt;T&gt;</code> is potentially a fat pointer. We have the data part of this fat pointer right, but there are many different cases of fat pointers so attempting to synthetize the rest is <strong>hard</strong>.</p>
  
  <p>As can be seen in the linked question, I can make it work for just trait objects:</p>
  
  <pre><code>impl&lt;T: ?Sized&gt; Weak&lt;T&gt; {
      pub fn new() -&gt; Weak&lt;T&gt; {
          unsafe {
              let boxed = Box::into_raw(box RcBox {
                  strong: Cell::new(0),
                  weak: Cell::new(1),
                  value: (),
              });
  
              let ptr = if size_of::&lt;*mut ()&gt;() == size_of::&lt;*mut T&gt;() {
                  let ptr: *mut RcBox&lt;T&gt; = transmute_copy(&amp;boxed);
                  ptr
              } else {
                  let ptr: *mut RcBox&lt;T&gt; = transmute_copy(&amp;TraitObject {
                      data: boxed as *mut (),
                      vtable: null_mut(),
                  });
                  ptr
              };
  
              Weak { ptr: Shared::new(ptr) }
          }
      }
  }
  </code></pre>
  
  <p>However this won't work with <code>str</code> (for example).</p>
  
  <p>I made another attempt trying to isolate the fixed-size portion of <code>RcBox</code> while letting the compiler infer the fat part of the pointer:</p>
  
  <pre><code>struct RcBox&lt;T: ?Sized&gt; {
      counters: RcBoxCounters&lt;T&gt;,
      value: T,
  }
  
  struct RcBoxCounters&lt;T: ?Sized&gt; {
      strong: Cell&lt;usize&gt;,
      weak: Cell&lt;usize&gt;,
      _phantom: PhantomData&lt;T&gt;,
  }
  
  impl&lt;T: ?Sized&gt; Weak&lt;T&gt; {
      pub fn new() -&gt; Weak&lt;T&gt; {
          unsafe {
              let boxed = Box::into_raw(box RcBox::Counters::new(0, 1));
              Weak { ptr: Shared::new(boxed as *mut RcBox&lt;T&gt;) }
          }
      }
  }
  </code></pre>
  
  <p>which sounds very clever until the compiler squashes your enthusiasm:</p>
  
  <blockquote>
    <pre class="lang-none prettyprint-override"><code>error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions
    --&gt; &lt;anon&gt;:58:40
     |
  58 | impl&lt;T: ?Sized + Unsize&lt;U&gt;, U: ?Sized&gt; CoerceUnsized&lt;RcBox&lt;U&gt;&gt; for RcBox&lt;T&gt; {}
     |                                        ^^^^^^^^^^^^^^^^^^^^^^^ 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&lt;T&gt; to RcBoxCounters&lt;U&gt;), value (T to U)
  </code></pre>
  </blockquote>
  
  <p>That is:</p>
  
  <ul>
  <li>I think that to let the compiler synthesize the fat part I need a <code>PhantomData</code> in <code>RcBoxCounters</code>,</li>
  <li>however doing so requires 2 conversions for the coercion, which is not allowed.</li>
  </ul>
  
  <hr>
  
  <p>So, is there a way to fix <code>Weak::new()</code> so that it stops allocating extraneous (unnecessary) memory?</p>
  
  <p><em>Note: I do mean allocating only space for the two counters, allocating large and trimming afterward does NOT help.</em></p>
  
  <p><em>Note: It has been remarked that one could use an <code>Option</code> or special value to denote the absence of value. This requires branching on each method, which may not be desirable. I prefer learning to fiddle with fat pointers.</em></p>