@@ -33,7 +33,7 @@ pub fn alloc(size: usize) -> *mut Region {
33
33
/// Similar to alloc, but instead of creating a new vector it consumes an existing one and returns
34
34
/// a pointer to the Region (preventing the memory from being freed until explicitly called later).
35
35
///
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 .
37
37
pub fn release_buffer ( buffer : Vec < u8 > ) -> * mut Region {
38
38
let region = build_region ( & buffer) ;
39
39
mem:: forget ( buffer) ;
@@ -69,15 +69,83 @@ pub unsafe fn consume_region(ptr: *mut Region) -> Vec<u8> {
69
69
)
70
70
}
71
71
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
+
72
136
/// Returns a box of a Region, which can be sent over a call to extern
73
137
/// note that this DOES NOT take ownership of the data, and we MUST NOT consume_region
74
138
/// the resulting data.
75
139
/// 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.
78
146
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" ) ,
81
149
u32:: try_from ( data. len ( ) ) . expect ( "length doesn't fit in u32" ) ,
82
150
)
83
151
}
0 commit comments