11use core:: ptr;
22use core:: mem:: { forget, size_of} ;
3+ use core:: marker:: PhantomData ;
4+ use core:: cell:: Cell ;
35use super :: Unpark ;
46
5- /// Maximum size in bytes that will fit in a `UnparkObject`.
6- /// TODO: What should this value be?
7- /// Should we expose this?
8- /// We probably want to say that this value may increase but never decrease in a 1.x release.
9- const MAX_OBJ_BYTES : usize = 64 ;
7+ /// Maximum size of `T` in `UnparkHandle<T>`, in bytes.
8+ /// Configurable by the FUTURES_MAX_UNPARK_BYTES env var at compile-time.
9+ pub const MAX_UNPARK_BYTES : usize = include ! ( concat!( env!( "OUT_DIR" ) , "/max_unpark_bytes.txt" ) ) ;
1010
1111/// A VTable that knows how to clone because the data has a maximum size.
1212#[ derive( Copy ) ]
1313struct UnparkVtable {
1414 unpark : fn ( * const ( ) ) ,
15- clone_to_byte_buffer : fn ( * const ( ) ) -> [ u8 ; MAX_OBJ_BYTES ] ,
15+ clone_to_byte_buffer : fn ( * const ( ) ) -> [ u8 ; MAX_UNPARK_BYTES ] ,
1616 drop_in_place : unsafe fn ( * mut ( ) ) ,
1717}
1818
@@ -24,7 +24,7 @@ impl Clone for UnparkVtable {
2424
2525impl UnparkVtable {
2626 fn new < T : Unpark + Clone > ( ) -> UnparkVtable {
27- assert ! ( size_of:: <T >( ) <= MAX_OBJ_BYTES ) ;
27+ assert ! ( size_of:: <T >( ) <= MAX_UNPARK_BYTES ) ;
2828 UnparkVtable {
2929 unpark : Self :: call_unpark :: < T > ,
3030 clone_to_byte_buffer : Self :: clone_to_byte_buffer :: < T > ,
@@ -37,9 +37,9 @@ impl UnparkVtable {
3737 downcasted. unpark ( )
3838 }
3939
40- /// Returns array with bytes of the cloned data. Make sure data is shorter than MAX_OBJ_BYTES .
40+ /// Returns array with bytes of the cloned data. Safe if data is shorter than MAX_UNPARK_BYTES .
4141 /// The caller owns the new data and is responsible for dropping it with `drop_in_place<T>`.
42- fn clone_to_byte_buffer < T : Clone > ( data : * const ( ) ) -> [ u8 ; MAX_OBJ_BYTES ] {
42+ fn clone_to_byte_buffer < T : Clone > ( data : * const ( ) ) -> [ u8 ; MAX_UNPARK_BYTES ] {
4343 let downcasted = unsafe { & * ( data as * const _ as * const T ) } ;
4444 obliviate ( downcasted. clone ( ) )
4545 }
@@ -57,7 +57,6 @@ impl UnparkVtable {
5757/// an `Arc` before passing it to the `UnparkHandle`.
5858///
5959/// # Deciding whether to use an `Arc`
60- /// If your `unpark` is not `Clone` or has lifetime parameters then you must use an `Arc`.
6160/// If you use inner mutability in your `unpark`, then you should carefully
6261/// consider what happens when it is cloned and what is the behaviour you want.
6362/// Inner mutability aside, the only difference between using or not an `Arc` should be performance.
@@ -68,35 +67,32 @@ impl UnparkVtable {
6867pub struct UnparkHandle {
6968 // A custom trait object that takes ownership of the data as a slice of bytes.
7069 // Can clone it's `data`, goes inside a `Task`.
71- data : [ u8 ; MAX_OBJ_BYTES ] ,
70+ data : [ u8 ; MAX_UNPARK_BYTES ] ,
7271 vtable : UnparkVtable ,
72+ not_sync : PhantomData < Cell < ( ) > > // Cell is Send but not Sync, convenient.
7373}
7474
75- // Means `Task` is not `Sync`.
76- //impl !Sync for UnparkHandle {}
77-
7875impl UnparkHandle {
7976 /// Constructs a `UnparkHandle`.
8077 /// A `Task` handle returned by `park` will contain a clone of the `unpark`
8178 /// argument provided here. You may want to wrap `unpark` in an `Arc`.
8279 ///
8380 /// # Panic
8481 /// Panics if the size of 'T' is too large. If you get a panic try wrapping the argument
85- /// in an `Arc`.
82+ /// in an `Arc` or setting the FUTURES_MAX_UNPARK_BYTES env var to the size of `T`.
83+ /// After changing FUTURES_MAX_UNPARK_BYTES you need to recompile `futures`.
8684 pub fn new < T : Unpark + Clone + ' static > ( unpark : T ) -> UnparkHandle {
87- if size_of :: < T > ( ) > MAX_OBJ_BYTES {
88- // TODO: Panicking here seems reasonable and could be a compile time error when we
89- // get a const sytem in Rust. But what about libraries that pass a user supplied type as T?
90- // Should we expose MAX_OBJ_BYTES? Offer a version that return an error?
91- // We could auto-fallback to Arc, with the downside that we need two UnparkHandle constructors,
92- // one with fallback where the user doesn't care because Arc doesn't change his semantics,
93- // one without fallback where he cares and wants to decide for himself between Arc or no Arc.
94- panic ! ( "The size of T is {} bytes which is too large. Try wrapping the unpark argument in an Arc." ) ;
85+ if size_of :: < T > ( ) > MAX_UNPARK_BYTES {
86+ // Panicking is reasonable since it's easy to catch and fix when testing.
87+ // Could be a compile time error when we get a const system in Rust.
88+ // Libraries that pass a user supplied T should do this check themselves if they want to avoid the panic.
89+ panic ! ( "The size of T is {} bytes which is too large. Try wrapping the unpark argument in an Arc or setting the FUTURES_MAX_UNPARK_BYTES env var." ) ;
9590 }
9691
9792 UnparkHandle {
9893 data : obliviate ( unpark) ,
9994 vtable : UnparkVtable :: new :: < T > ( ) ,
95+ not_sync : PhantomData
10096 }
10197 }
10298}
@@ -113,7 +109,7 @@ impl Clone for UnparkHandle {
113109 fn clone ( & self ) -> Self {
114110 UnparkHandle {
115111 data : ( self . vtable . clone_to_byte_buffer ) ( & self . data as * const _ as * const ( ) ) ,
116- vtable : self . vtable ,
112+ .. * self
117113 }
118114 }
119115}
@@ -126,10 +122,10 @@ impl Unpark for UnparkHandle {
126122
127123/// Turns the victim into raw bytes and forgets it.
128124/// The caller now owns the value and is responsible for dropping it with 'drop_in_place<T>'.
129- fn obliviate < T > ( victim : T ) -> [ u8 ; MAX_OBJ_BYTES ] {
125+ fn obliviate < T > ( victim : T ) -> [ u8 ; MAX_UNPARK_BYTES ] {
130126 let size = size_of :: < T > ( ) ;
131- assert ! ( size < MAX_OBJ_BYTES ) ;
132- let mut buffer = [ 0 ; MAX_OBJ_BYTES ] ;
127+ assert ! ( size < MAX_UNPARK_BYTES ) ;
128+ let mut buffer = [ 0 ; MAX_UNPARK_BYTES ] ;
133129 // View victim and buffer as raw bytes.
134130 let victim_ptr = & victim as * const _ as * const u8 ;
135131 let buffer_ptr = & mut buffer as * mut _ as * mut u8 ;
0 commit comments