@@ -33,7 +33,7 @@ pub fn alloc(size: usize) -> *mut Region {
3333/// Similar to alloc, but instead of creating a new vector it consumes an existing one and returns
3434/// a pointer to the Region (preventing the memory from being freed until explicitly called later).
3535///
36- /// The resulting Region has capacity = length, i.e. the buffer's capacity is ignored .
36+ /// The resulting Region spans the entire region allocated by the vector, preserving the length and capacity components .
3737pub fn release_buffer ( buffer : Vec < u8 > ) -> * mut Region {
3838 let region = build_region ( & buffer) ;
3939 mem:: forget ( buffer) ;
@@ -69,15 +69,83 @@ pub unsafe fn consume_region(ptr: *mut Region) -> Vec<u8> {
6969 )
7070}
7171
72+ /// Element that can be used to construct a new `Box<Region>`
73+ ///
74+ /// # Safety
75+ ///
76+ /// The following invariant must be upheld:
77+ ///
78+ /// - full allocated capacity == value returned by capacity
79+ ///
80+ /// This is important to uphold the safety invariant of the `dealloc` method, which requires us to pass the same Layout
81+ /// into it as was used to allocate a memory region.
82+ /// And since `size` is one of the parameters, it is important to pass in the exact same capacity.
83+ ///
84+ /// See: <https://doc.rust-lang.org/stable/alloc/alloc/trait.GlobalAlloc.html#safety-2>
85+ pub unsafe trait RegionSource {
86+ fn ptr ( & self ) -> * const u8 ;
87+ fn len ( & self ) -> usize ;
88+ fn capacity ( & self ) -> usize ;
89+ }
90+
91+ unsafe impl RegionSource for & [ u8 ] {
92+ fn ptr ( & self ) -> * const u8 {
93+ self . as_ptr ( )
94+ }
95+
96+ fn len ( & self ) -> usize {
97+ ( * self ) . len ( )
98+ }
99+
100+ fn capacity ( & self ) -> usize {
101+ self . len ( )
102+ }
103+ }
104+
105+ unsafe impl RegionSource for Vec < u8 > {
106+ fn ptr ( & self ) -> * const u8 {
107+ self . as_ptr ( )
108+ }
109+
110+ fn len ( & self ) -> usize {
111+ self . len ( )
112+ }
113+
114+ fn capacity ( & self ) -> usize {
115+ self . capacity ( )
116+ }
117+ }
118+
119+ unsafe impl < T : ?Sized > RegionSource for & T
120+ where
121+ T : RegionSource ,
122+ {
123+ fn ptr ( & self ) -> * const u8 {
124+ ( * * self ) . ptr ( )
125+ }
126+
127+ fn len ( & self ) -> usize {
128+ ( * * self ) . len ( )
129+ }
130+
131+ fn capacity ( & self ) -> usize {
132+ ( * * self ) . capacity ( )
133+ }
134+ }
135+
72136/// Returns a box of a Region, which can be sent over a call to extern
73137/// note that this DOES NOT take ownership of the data, and we MUST NOT consume_region
74138/// the resulting data.
75139/// The Box must be dropped (with scope), but not the data
76- pub fn build_region ( data : & [ u8 ] ) -> Box < Region > {
77- let data_ptr = data. as_ptr ( ) as usize ;
140+ pub fn build_region < S > ( data : S ) -> Box < Region >
141+ where
142+ S : RegionSource ,
143+ {
144+ // Well, this technically violates pointer provenance rules.
145+ // But there isn't a stable API for it, so that's the best we can do, I guess.
78146 build_region_from_components (
79- u32:: try_from ( data_ptr ) . expect ( "pointer doesn't fit in u32" ) ,
80- u32:: try_from ( data. len ( ) ) . expect ( "length doesn't fit in u32" ) ,
147+ u32:: try_from ( data . ptr ( ) as usize ) . expect ( "pointer doesn't fit in u32" ) ,
148+ u32:: try_from ( data. capacity ( ) ) . expect ( "capacity doesn't fit in u32" ) ,
81149 u32:: try_from ( data. len ( ) ) . expect ( "length doesn't fit in u32" ) ,
82150 )
83151}
0 commit comments