@@ -7,7 +7,10 @@ use std::num::NonZeroUsize;
77use log:: debug;
88
99/// 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 {
1114 const BYTE_LEN : usize ;
1215
1316 // FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
@@ -37,7 +40,7 @@ macro_rules! fixed_size_encoding_byte_len_and_defaults {
3740 b. len( ) / BYTE_LEN ,
3841 )
3942 } ;
40- Self :: from_bytes( & b[ i] )
43+ FixedSizeEncoding :: from_bytes( & b[ i] )
4144 }
4245 fn write_to_bytes_at( self , b: & mut [ u8 ] , i: usize ) {
4346 const BYTE_LEN : usize = $byte_len;
@@ -68,38 +71,71 @@ impl FixedSizeEncoding for u32 {
6871 }
6972}
7073
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
76118// when building it, and `Lazy<Table<T>>` or `&Table<T>` when reading it.
77119// Sadly, that doesn't work for `DefPerTable`, which is `(Table<T>, Table<T>)`,
78120// 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).
80124 bytes : Vec < u8 > ,
81125 _marker : PhantomData < T > ,
82126}
83127
84- impl < T : LazyMeta < Meta = ( ) > > Table < T > {
128+ impl < T > Table < T > where Option < T > : FixedSizeEncoding {
85129 pub fn new ( len : usize ) -> Self {
86130 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 ] ,
88133 _marker : PhantomData ,
89134 }
90135 }
91136
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) ;
103139 }
104140
105141 pub fn encode ( & self , buf : & mut Encoder ) -> Lazy < Self > {
@@ -112,49 +148,44 @@ impl<T: LazyMeta<Meta = ()>> Table<T> {
112148 }
113149}
114150
115- impl < T : LazyMeta < Meta = ( ) > > LazyMeta for Table < T > {
151+ impl < T > LazyMeta for Table < T > where Option < T > : FixedSizeEncoding {
116152 type Meta = usize ;
117153
118154 fn min_size ( len : usize ) -> usize {
119155 len
120156 }
121157}
122158
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).
125161 #[ 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 > {
127163 debug ! ( "Table::lookup: index={:?} len={:?}" , i, self . meta) ;
128164
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)
134166 }
135167}
136168
137-
138169/// Per-definition table, similar to `Table` but keyed on `DefIndex`.
139170/// 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 {
141172 lo : Table < T > ,
142173 hi : Table < T > ,
143174}
144175
145- impl < T : LazyMeta < Meta = ( ) > > PerDefTable < T > {
176+ impl < T > PerDefTable < T > where Option < T > : FixedSizeEncoding {
146177 pub fn new ( ( max_index_lo, max_index_hi) : ( usize , usize ) ) -> Self {
147178 PerDefTable {
148179 lo : Table :: new ( max_index_lo) ,
149180 hi : Table :: new ( max_index_hi) ,
150181 }
151182 }
152183
153- pub fn record ( & mut self , def_id : DefId , entry : Lazy < T > ) {
184+ pub fn set ( & mut self , def_id : DefId , value : T ) {
154185 assert ! ( def_id. is_local( ) ) ;
155186 let space_index = def_id. index . address_space ( ) . index ( ) ;
156187 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 ) ;
158189 }
159190
160191 pub fn encode ( & self , buf : & mut Encoder ) -> Lazy < Self > {
@@ -169,15 +200,15 @@ impl<T: LazyMeta<Meta = ()>> PerDefTable<T> {
169200 }
170201}
171202
172- impl < T : LazyMeta < Meta = ( ) > > LazyMeta for PerDefTable < T > {
203+ impl < T > LazyMeta for PerDefTable < T > where Option < T > : FixedSizeEncoding {
173204 type Meta = [ <Table < T > as LazyMeta >:: Meta ; 2 ] ;
174205
175206 fn min_size ( [ lo, hi] : Self :: Meta ) -> usize {
176207 Table :: < T > :: min_size ( lo) + Table :: < T > :: min_size ( hi)
177208 }
178209}
179210
180- impl < T : Encodable > Lazy < PerDefTable < T > > {
211+ impl < T > Lazy < PerDefTable < T > > where Option < T > : FixedSizeEncoding {
181212 fn table_for_space ( & self , space : DefIndexAddressSpace ) -> Lazy < Table < T > > {
182213 let space_index = space. index ( ) ;
183214 let offset = space_index. checked_sub ( 1 ) . map_or ( 0 , |i| self . meta [ i] ) ;
@@ -187,10 +218,10 @@ impl<T: Encodable> Lazy<PerDefTable<T>> {
187218 )
188219 }
189220
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).
191222 #[ 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 > {
193224 self . table_for_space ( def_index. address_space ( ) )
194- . lookup ( bytes, def_index. as_array_index ( ) )
225+ . get ( bytes, def_index. as_array_index ( ) )
195226 }
196227}
0 commit comments