@@ -555,3 +555,115 @@ fn from_raw_parts() {
555
555
assert_eq ! ( ptr:: from_raw_parts_mut( address, 5 ) , slice_ptr. as_ptr( ) ) ;
556
556
assert_eq ! ( NonNull :: from_raw_parts( NonNull :: new( address) . unwrap( ) , 5 ) , slice_ptr) ;
557
557
}
558
+
559
+ #[ test]
560
+ #[ cfg( not( bootstrap) ) ]
561
+ fn thin_box ( ) {
562
+ let foo = ThinBox :: < dyn Display > :: new ( 4 ) ;
563
+ assert_eq ! ( foo. to_string( ) , "4" ) ;
564
+ drop ( foo) ;
565
+ let bar = ThinBox :: < dyn Display > :: new ( 7 ) ;
566
+ assert_eq ! ( bar. to_string( ) , "7" ) ;
567
+
568
+ // A slightly more interesting library that could be built on top of metadata APIs.
569
+ //
570
+ // * It could be generalized to any `T: ?Sized` (not just trait object)
571
+ // if `{size,align}_of_for_meta<T: ?Sized>(T::Metadata)` are added.
572
+ // * Constructing a `ThinBox` without consuming and deallocating a `Box`
573
+ // requires either the unstable `Unsize` marker trait,
574
+ // or the unstable `unsized_locals` language feature,
575
+ // or taking `&dyn T` and restricting to `T: Copy`.
576
+
577
+ use std:: alloc:: * ;
578
+ use std:: marker:: PhantomData ;
579
+
580
+ struct ThinBox < T >
581
+ where
582
+ T : ?Sized + Pointee < Metadata = DynMetadata < T > > ,
583
+ {
584
+ ptr : NonNull < DynMetadata < T > > ,
585
+ phantom : PhantomData < T > ,
586
+ }
587
+
588
+ impl < T > ThinBox < T >
589
+ where
590
+ T : ?Sized + Pointee < Metadata = DynMetadata < T > > ,
591
+ {
592
+ pub fn new < Value : std:: marker:: Unsize < T > > ( value : Value ) -> Self {
593
+ let unsized_: & T = & value;
594
+ let meta = metadata ( unsized_) ;
595
+ let meta_layout = Layout :: for_value ( & meta) ;
596
+ let value_layout = Layout :: for_value ( & value) ;
597
+ let ( layout, offset) = meta_layout. extend ( value_layout) . unwrap ( ) ;
598
+ // `DynMetadata` is pointer-sized:
599
+ assert ! ( layout. size( ) > 0 ) ;
600
+ // If `ThinBox<T>` is generalized to any `T: ?Sized`,
601
+ // handle ZSTs with a dangling pointer without going through `alloc()`,
602
+ // like `Box<T>` does.
603
+ unsafe {
604
+ let ptr = NonNull :: new ( alloc ( layout) )
605
+ . unwrap_or_else ( || handle_alloc_error ( layout) )
606
+ . cast :: < DynMetadata < T > > ( ) ;
607
+ ptr. as_ptr ( ) . write ( meta) ;
608
+ ptr. cast :: < u8 > ( ) . as_ptr ( ) . add ( offset) . cast :: < Value > ( ) . write ( value) ;
609
+ Self { ptr, phantom : PhantomData }
610
+ }
611
+ }
612
+
613
+ fn meta ( & self ) -> DynMetadata < T > {
614
+ unsafe { * self . ptr . as_ref ( ) }
615
+ }
616
+
617
+ fn layout ( & self ) -> ( Layout , usize ) {
618
+ let meta = self . meta ( ) ;
619
+ Layout :: for_value ( & meta) . extend ( meta. layout ( ) ) . unwrap ( )
620
+ }
621
+
622
+ fn value_ptr ( & self ) -> * const T {
623
+ let ( _, offset) = self . layout ( ) ;
624
+ let data_ptr = unsafe { self . ptr . cast :: < u8 > ( ) . as_ptr ( ) . add ( offset) } ;
625
+ ptr:: from_raw_parts ( data_ptr. cast ( ) , self . meta ( ) )
626
+ }
627
+
628
+ fn value_mut_ptr ( & mut self ) -> * mut T {
629
+ let ( _, offset) = self . layout ( ) ;
630
+ // FIXME: can this line be shared with the same in `value_ptr()`
631
+ // without upsetting Stacked Borrows?
632
+ let data_ptr = unsafe { self . ptr . cast :: < u8 > ( ) . as_ptr ( ) . add ( offset) } ;
633
+ from_raw_parts_mut ( data_ptr. cast ( ) , self . meta ( ) )
634
+ }
635
+ }
636
+
637
+ impl < T > std:: ops:: Deref for ThinBox < T >
638
+ where
639
+ T : ?Sized + Pointee < Metadata = DynMetadata < T > > ,
640
+ {
641
+ type Target = T ;
642
+
643
+ fn deref ( & self ) -> & T {
644
+ unsafe { & * self . value_ptr ( ) }
645
+ }
646
+ }
647
+
648
+ impl < T > std:: ops:: DerefMut for ThinBox < T >
649
+ where
650
+ T : ?Sized + Pointee < Metadata = DynMetadata < T > > ,
651
+ {
652
+ fn deref_mut ( & mut self ) -> & mut T {
653
+ unsafe { & mut * self . value_mut_ptr ( ) }
654
+ }
655
+ }
656
+
657
+ impl < T > std:: ops:: Drop for ThinBox < T >
658
+ where
659
+ T : ?Sized + Pointee < Metadata = DynMetadata < T > > ,
660
+ {
661
+ fn drop ( & mut self ) {
662
+ let ( layout, _) = self . layout ( ) ;
663
+ unsafe {
664
+ drop_in_place :: < T > ( & mut * * self ) ;
665
+ dealloc ( self . ptr . cast ( ) . as_ptr ( ) , layout) ;
666
+ }
667
+ }
668
+ }
669
+ }
0 commit comments