@@ -7,7 +7,10 @@ use std::num::NonZeroUsize;
7
7
use log:: debug;
8
8
9
9
/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
10
- pub trait FixedSizeEncoding {
10
+ /// Used mainly for Lazy positions and lengths.
11
+ /// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
12
+ /// but this has no impact on safety.
13
+ pub trait FixedSizeEncoding : Default {
11
14
const BYTE_LEN : usize ;
12
15
13
16
// FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
@@ -37,7 +40,7 @@ macro_rules! fixed_size_encoding_byte_len_and_defaults {
37
40
b. len( ) / BYTE_LEN ,
38
41
)
39
42
} ;
40
- Self :: from_bytes( & b[ i] )
43
+ FixedSizeEncoding :: from_bytes( & b[ i] )
41
44
}
42
45
fn write_to_bytes_at( self , b: & mut [ u8 ] , i: usize ) {
43
46
const BYTE_LEN : usize = $byte_len;
@@ -68,38 +71,71 @@ impl FixedSizeEncoding for u32 {
68
71
}
69
72
}
70
73
71
- /// Random-access position table, allowing encoding in an arbitrary order
72
- /// (e.g. while visiting the definitions of a crate), and on-demand decoding
73
- /// of specific indices (e.g. queries for per-definition data).
74
- /// Similar to `Vec<Lazy<T>>`, but with zero-copy decoding.
75
- // FIXME(eddyb) newtype `[u8]` here, such that `Box<Table<T>>` would be used
74
+ // NOTE(eddyb) there could be an impl for `usize`, which would enable a more
75
+ // generic `Lazy<T>` impl, but in the general case we might not need / want to
76
+ // fit every `usize` in `u32`.
77
+ impl < T : Encodable > FixedSizeEncoding for Option < Lazy < T > > {
78
+ fixed_size_encoding_byte_len_and_defaults ! ( u32 :: BYTE_LEN ) ;
79
+
80
+ fn from_bytes ( b : & [ u8 ] ) -> Self {
81
+ Some ( Lazy :: from_position ( NonZeroUsize :: new ( u32:: from_bytes ( b) as usize ) ?) )
82
+ }
83
+
84
+ fn write_to_bytes ( self , b : & mut [ u8 ] ) {
85
+ let position = self . map_or ( 0 , |lazy| lazy. position . get ( ) ) ;
86
+ let position_u32 = position as u32 ;
87
+ assert_eq ! ( position_u32 as usize , position) ;
88
+
89
+ position_u32. write_to_bytes ( b)
90
+ }
91
+ }
92
+
93
+ impl < T : Encodable > FixedSizeEncoding for Option < Lazy < [ T ] > > {
94
+ fixed_size_encoding_byte_len_and_defaults ! ( u32 :: BYTE_LEN * 2 ) ;
95
+
96
+ fn from_bytes ( b : & [ u8 ] ) -> Self {
97
+ Some ( Lazy :: from_position_and_meta (
98
+ <Option < Lazy < T > > >:: from_bytes ( b) ?. position ,
99
+ u32:: from_bytes ( & b[ u32:: BYTE_LEN ..] ) as usize ,
100
+ ) )
101
+ }
102
+
103
+ fn write_to_bytes ( self , b : & mut [ u8 ] ) {
104
+ self . map ( |lazy| Lazy :: < T > :: from_position ( lazy. position ) )
105
+ . write_to_bytes ( b) ;
106
+
107
+ let len = self . map_or ( 0 , |lazy| lazy. meta ) ;
108
+ let len_u32 = len as u32 ;
109
+ assert_eq ! ( len_u32 as usize , len) ;
110
+
111
+ len_u32. write_to_bytes ( & mut b[ u32:: BYTE_LEN ..] ) ;
112
+ }
113
+ }
114
+
115
+ /// Random-access table, similar to `Vec<Option<T>>`, but without requiring
116
+ /// encoding or decoding all the values eagerly and in-order.
117
+ // FIXME(eddyb) replace `Vec` with `[_]` here, such that `Box<Table<T>>` would be used
76
118
// when building it, and `Lazy<Table<T>>` or `&Table<T>` when reading it.
77
119
// Sadly, that doesn't work for `DefPerTable`, which is `(Table<T>, Table<T>)`,
78
120
// and so would need two lengths in its metadata, which is not supported yet.
79
- pub struct Table < T : LazyMeta < Meta = ( ) > > {
121
+ pub struct Table < T > where Option < T > : FixedSizeEncoding {
122
+ // FIXME(eddyb) store `[u8; <Option<T>>::BYTE_LEN]` instead of `u8` in `Vec`,
123
+ // once that starts being allowed by the compiler (i.e. lazy normalization).
80
124
bytes : Vec < u8 > ,
81
125
_marker : PhantomData < T > ,
82
126
}
83
127
84
- impl < T : LazyMeta < Meta = ( ) > > Table < T > {
128
+ impl < T > Table < T > where Option < T > : FixedSizeEncoding {
85
129
pub fn new ( len : usize ) -> Self {
86
130
Table {
87
- bytes : vec ! [ 0 ; len * 4 ] ,
131
+ // FIXME(eddyb) only allocate and encode as many entries as needed.
132
+ bytes : vec ! [ 0 ; len * <Option <T >>:: BYTE_LEN ] ,
88
133
_marker : PhantomData ,
89
134
}
90
135
}
91
136
92
- pub fn record ( & mut self , i : usize , entry : Lazy < T > ) {
93
- let position = entry. position . get ( ) as u32 ;
94
- assert_eq ! ( position as usize , entry. position. get( ) ) ;
95
-
96
- assert ! ( u32 :: read_from_bytes_at( & self . bytes, i) == 0 ,
97
- "recorded position for index {:?} twice, first at {:?} and now at {:?}" ,
98
- i,
99
- u32 :: read_from_bytes_at( & self . bytes, i) ,
100
- position) ;
101
-
102
- position. write_to_bytes_at ( & mut self . bytes , i)
137
+ pub fn set ( & mut self , i : usize , value : T ) {
138
+ Some ( value) . write_to_bytes_at ( & mut self . bytes , i) ;
103
139
}
104
140
105
141
pub fn encode ( & self , buf : & mut Encoder ) -> Lazy < Self > {
@@ -112,49 +148,44 @@ impl<T: LazyMeta<Meta = ()>> Table<T> {
112
148
}
113
149
}
114
150
115
- impl < T : LazyMeta < Meta = ( ) > > LazyMeta for Table < T > {
151
+ impl < T > LazyMeta for Table < T > where Option < T > : FixedSizeEncoding {
116
152
type Meta = usize ;
117
153
118
154
fn min_size ( len : usize ) -> usize {
119
155
len
120
156
}
121
157
}
122
158
123
- impl < T : Encodable > Lazy < Table < T > > {
124
- /// Given the metadata, extract out the offset of a particular index (if any).
159
+ impl < T > Lazy < Table < T > > where Option < T > : FixedSizeEncoding {
160
+ /// Given the metadata, extract out the value at a particular index (if any).
125
161
#[ inline( never) ]
126
- pub fn lookup ( & self , bytes : & [ u8 ] , i : usize ) -> Option < Lazy < T > > {
162
+ pub fn get ( & self , bytes : & [ u8 ] , i : usize ) -> Option < T > {
127
163
debug ! ( "Table::lookup: index={:?} len={:?}" , i, self . meta) ;
128
164
129
- let bytes = & bytes[ self . position . get ( ) ..] [ ..self . meta ] ;
130
- let position = u32:: read_from_bytes_at ( bytes, i) ;
131
- debug ! ( "Table::lookup: position={:?}" , position) ;
132
-
133
- NonZeroUsize :: new ( position as usize ) . map ( Lazy :: from_position)
165
+ <Option < T > >:: read_from_bytes_at ( & bytes[ self . position . get ( ) ..] [ ..self . meta ] , i)
134
166
}
135
167
}
136
168
137
-
138
169
/// Per-definition table, similar to `Table` but keyed on `DefIndex`.
139
170
/// Needed because of the two `DefIndexAddressSpace`s a `DefIndex` can be in.
140
- pub struct PerDefTable < T : LazyMeta < Meta = ( ) > > {
171
+ pub struct PerDefTable < T > where Option < T > : FixedSizeEncoding {
141
172
lo : Table < T > ,
142
173
hi : Table < T > ,
143
174
}
144
175
145
- impl < T : LazyMeta < Meta = ( ) > > PerDefTable < T > {
176
+ impl < T > PerDefTable < T > where Option < T > : FixedSizeEncoding {
146
177
pub fn new ( ( max_index_lo, max_index_hi) : ( usize , usize ) ) -> Self {
147
178
PerDefTable {
148
179
lo : Table :: new ( max_index_lo) ,
149
180
hi : Table :: new ( max_index_hi) ,
150
181
}
151
182
}
152
183
153
- pub fn record ( & mut self , def_id : DefId , entry : Lazy < T > ) {
184
+ pub fn set ( & mut self , def_id : DefId , value : T ) {
154
185
assert ! ( def_id. is_local( ) ) ;
155
186
let space_index = def_id. index . address_space ( ) . index ( ) ;
156
187
let array_index = def_id. index . as_array_index ( ) ;
157
- [ & mut self . lo , & mut self . hi ] [ space_index] . record ( array_index, entry ) ;
188
+ [ & mut self . lo , & mut self . hi ] [ space_index] . set ( array_index, value ) ;
158
189
}
159
190
160
191
pub fn encode ( & self , buf : & mut Encoder ) -> Lazy < Self > {
@@ -169,15 +200,15 @@ impl<T: LazyMeta<Meta = ()>> PerDefTable<T> {
169
200
}
170
201
}
171
202
172
- impl < T : LazyMeta < Meta = ( ) > > LazyMeta for PerDefTable < T > {
203
+ impl < T > LazyMeta for PerDefTable < T > where Option < T > : FixedSizeEncoding {
173
204
type Meta = [ <Table < T > as LazyMeta >:: Meta ; 2 ] ;
174
205
175
206
fn min_size ( [ lo, hi] : Self :: Meta ) -> usize {
176
207
Table :: < T > :: min_size ( lo) + Table :: < T > :: min_size ( hi)
177
208
}
178
209
}
179
210
180
- impl < T : Encodable > Lazy < PerDefTable < T > > {
211
+ impl < T > Lazy < PerDefTable < T > > where Option < T > : FixedSizeEncoding {
181
212
fn table_for_space ( & self , space : DefIndexAddressSpace ) -> Lazy < Table < T > > {
182
213
let space_index = space. index ( ) ;
183
214
let offset = space_index. checked_sub ( 1 ) . map_or ( 0 , |i| self . meta [ i] ) ;
@@ -187,10 +218,10 @@ impl<T: Encodable> Lazy<PerDefTable<T>> {
187
218
)
188
219
}
189
220
190
- /// Given the metadata, extract out the offset of a particular DefIndex (if any).
221
+ /// Given the metadata, extract out the value at a particular DefIndex (if any).
191
222
#[ inline( never) ]
192
- pub fn lookup ( & self , bytes : & [ u8 ] , def_index : DefIndex ) -> Option < Lazy < T > > {
223
+ pub fn get ( & self , bytes : & [ u8 ] , def_index : DefIndex ) -> Option < T > {
193
224
self . table_for_space ( def_index. address_space ( ) )
194
- . lookup ( bytes, def_index. as_array_index ( ) )
225
+ . get ( bytes, def_index. as_array_index ( ) )
195
226
}
196
227
}
0 commit comments