@@ -555,3 +555,115 @@ fn from_raw_parts() {
555555 assert_eq ! ( ptr:: from_raw_parts_mut( address, 5 ) , slice_ptr. as_ptr( ) ) ;
556556 assert_eq ! ( NonNull :: from_raw_parts( NonNull :: new( address) . unwrap( ) , 5 ) , slice_ptr) ;
557557}
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