1- use std:: ops:: ControlFlow ;
1+ use std:: ops:: { ControlFlow , RangeInclusive } ;
22
33use super :: { Byte , Def , Ref } ;
44
3232 Byte ( Byte ) ,
3333}
3434
35+ #[ derive( Debug , Copy , Clone , Eq , PartialEq ) ]
36+ pub ( crate ) enum Endian {
37+ Little ,
38+ Big ,
39+ }
40+
41+ #[ cfg( feature = "rustc" ) ]
42+ impl From < rustc_abi:: Endian > for Endian {
43+ fn from ( order : rustc_abi:: Endian ) -> Endian {
44+ match order {
45+ rustc_abi:: Endian :: Little => Endian :: Little ,
46+ rustc_abi:: Endian :: Big => Endian :: Big ,
47+ }
48+ }
49+ }
50+
3551impl < D , R > Tree < D , R >
3652where
3753 D : Def ,
@@ -59,17 +75,57 @@ where
5975
6076 /// A `Tree` representing the layout of `bool`.
6177 pub ( crate ) fn bool ( ) -> Self {
62- Self :: Byte ( Byte :: new ( 0x00 ..=0x01 ) )
78+ Self :: byte ( 0x00 ..=0x01 )
6379 }
6480
6581 /// A `Tree` whose layout matches that of a `u8`.
6682 pub ( crate ) fn u8 ( ) -> Self {
67- Self :: Byte ( Byte :: new ( 0x00 ..=0xFF ) )
83+ Self :: byte ( 0x00 ..=0xFF )
6884 }
6985
70- /// A `Tree` whose layout accepts exactly the given bit pattern.
71- pub ( crate ) fn from_bits ( bits : u8 ) -> Self {
72- Self :: Byte ( Byte :: from_val ( bits) )
86+ /// A `Tree` whose layout matches that of a `char`.
87+ pub ( crate ) fn char ( order : Endian ) -> Self {
88+ // `char`s can be in the following ranges:
89+ // - [0, 0xD7FF]
90+ // - [0xE000, 10FFFF]
91+ //
92+ // All other `char` values are illegal. We can thus represent a `char`
93+ // as a union of three possible layouts:
94+ // - 00 00 [00, D7] XX
95+ // - 00 00 [E0, FF] XX
96+ // - 00 [01, 10] XX XX
97+
98+ const _0: RangeInclusive < u8 > = 0 ..=0 ;
99+ const BYTE : RangeInclusive < u8 > = 0x00 ..=0xFF ;
100+ // OverB(B) = 0xD800,
101+ // UnderC(C) = 0xDFFF,
102+ let x = Self :: from_big_endian ( order, [ _0, _0, 0x00 ..=0xD7 , BYTE ] ) ;
103+ let y = Self :: from_big_endian ( order, [ _0, _0, 0xE0 ..=0xFF , BYTE ] ) ;
104+ let z = Self :: from_big_endian ( order, [ _0, 0x01 ..=0x10 , BYTE , BYTE ] ) ;
105+ Self :: alt ( [ x, y, z] )
106+ }
107+
108+ /// A `Tree` whose layout matches `std::num::NonZeroXxx`.
109+ #[ allow( dead_code) ]
110+ pub ( crate ) fn nonzero ( width_in_bytes : usize ) -> Self {
111+ const BYTE : RangeInclusive < u8 > = 0x00 ..=0xFF ;
112+ const NONZERO : RangeInclusive < u8 > = 0x01 ..=0xFF ;
113+
114+ ( 0 ..width_in_bytes)
115+ . map ( |nz_idx| {
116+ ( 0 ..width_in_bytes)
117+ . map ( |pos| Self :: byte ( if pos == nz_idx { NONZERO } else { BYTE } ) )
118+ . fold ( Self :: unit ( ) , Self :: then)
119+ } )
120+ . fold ( Self :: uninhabited ( ) , Self :: or)
121+ }
122+
123+ pub ( crate ) fn bytes < const N : usize , B : Into < Byte > > ( bytes : [ B ; N ] ) -> Self {
124+ Self :: seq ( bytes. map ( B :: into) . map ( Self :: Byte ) )
125+ }
126+
127+ pub ( crate ) fn byte ( byte : impl Into < Byte > ) -> Self {
128+ Self :: Byte ( byte. into ( ) )
73129 }
74130
75131 /// A `Tree` whose layout is a number of the given width.
@@ -125,13 +181,35 @@ where
125181 Self :: Byte ( ..) | Self :: Ref ( ..) | Self :: Def ( ..) => true ,
126182 }
127183 }
128- }
129184
130- impl < D , R > Tree < D , R >
131- where
132- D : Def ,
133- R : Ref ,
134- {
185+ /// Produces a `Tree` which represents a sequence of bytes stored in
186+ /// `order`.
187+ ///
188+ /// `bytes` is taken to be in big-endian byte order, and its order will be
189+ /// swapped if `order == Endian::Little`.
190+ pub ( crate ) fn from_big_endian < const N : usize , B : Into < Byte > > (
191+ order : Endian ,
192+ mut bytes : [ B ; N ] ,
193+ ) -> Self {
194+ if order == Endian :: Little {
195+ ( & mut bytes[ ..] ) . reverse ( ) ;
196+ }
197+
198+ Self :: bytes ( bytes)
199+ }
200+
201+ /// Produces a `Tree` where each of the trees in `trees` are sequenced one
202+ /// after another.
203+ pub ( crate ) fn seq < const N : usize > ( trees : [ Tree < D , R > ; N ] ) -> Self {
204+ trees. into_iter ( ) . fold ( Tree :: unit ( ) , Self :: then)
205+ }
206+
207+ /// Produces a `Tree` where each of the trees in `trees` are accepted as
208+ /// alternative layouts.
209+ pub ( crate ) fn alt < const N : usize > ( trees : [ Tree < D , R > ; N ] ) -> Self {
210+ trees. into_iter ( ) . fold ( Tree :: uninhabited ( ) , Self :: or)
211+ }
212+
135213 /// Produces a new `Tree` where `other` is sequenced after `self`.
136214 pub ( crate ) fn then ( self , other : Self ) -> Self {
137215 match ( self , other) {
@@ -172,7 +250,8 @@ where
172250#[ cfg( feature = "rustc" ) ]
173251pub ( crate ) mod rustc {
174252 use rustc_abi:: {
175- FieldIdx , FieldsShape , Layout , Size , TagEncoding , TyAndLayout , VariantIdx , Variants ,
253+ FieldIdx , FieldsShape , Layout , Size , TagEncoding , TyAbiInterface , TyAndLayout , VariantIdx ,
254+ Variants ,
176255 } ;
177256 use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutCx , LayoutError } ;
178257 use rustc_middle:: ty:: { self , AdtDef , AdtKind , List , ScalarInt , Ty , TyCtxt , TypeVisitableExt } ;
@@ -222,17 +301,17 @@ pub(crate) mod rustc {
222301
223302 ty:: Float ( nty) => {
224303 let width = nty. bit_width ( ) / 8 ;
225- Ok ( Self :: number ( width as _ ) )
304+ Ok ( Self :: number ( width. try_into ( ) . unwrap ( ) ) )
226305 }
227306
228307 ty:: Int ( nty) => {
229308 let width = nty. normalize ( pointer_size. bits ( ) as _ ) . bit_width ( ) . unwrap ( ) / 8 ;
230- Ok ( Self :: number ( width as _ ) )
309+ Ok ( Self :: number ( width. try_into ( ) . unwrap ( ) ) )
231310 }
232311
233312 ty:: Uint ( nty) => {
234313 let width = nty. normalize ( pointer_size. bits ( ) as _ ) . bit_width ( ) . unwrap ( ) / 8 ;
235- Ok ( Self :: number ( width as _ ) )
314+ Ok ( Self :: number ( width. try_into ( ) . unwrap ( ) ) )
236315 }
237316
238317 ty:: Tuple ( members) => Self :: from_tuple ( ( ty, layout) , members, cx) ,
@@ -249,11 +328,30 @@ pub(crate) mod rustc {
249328 . fold ( Tree :: unit ( ) , |tree, elt| tree. then ( elt) ) )
250329 }
251330
252- ty:: Adt ( adt_def, _args_ref) if !ty. is_box ( ) => match adt_def. adt_kind ( ) {
253- AdtKind :: Struct => Self :: from_struct ( ( ty, layout) , * adt_def, cx) ,
254- AdtKind :: Enum => Self :: from_enum ( ( ty, layout) , * adt_def, cx) ,
255- AdtKind :: Union => Self :: from_union ( ( ty, layout) , * adt_def, cx) ,
256- } ,
331+ ty:: Adt ( adt_def, _args_ref) if !ty. is_box ( ) => {
332+ let ( lo, hi) = cx. tcx ( ) . layout_scalar_valid_range ( adt_def. did ( ) ) ;
333+
334+ // TODO: Figure out when `(lo, hi)` implies that we should
335+ // use the `Tree::nonzero` constructor.
336+
337+ use core:: ops:: Bound :: * ;
338+ let is_transparent = Ty :: is_transparent ( TyAndLayout { ty, layout } ) ;
339+ match ( adt_def. adt_kind ( ) , lo, hi) {
340+ ( AdtKind :: Struct , Unbounded , Unbounded ) => {
341+ Self :: from_struct ( ( ty, layout) , * adt_def, cx)
342+ }
343+ ( AdtKind :: Struct , Included ( lo) , Included ( hi) ) if is_transparent => {
344+ Self :: from_struct ( ( ty, layout) , * adt_def, cx)
345+ }
346+ ( AdtKind :: Enum , Unbounded , Unbounded ) => {
347+ Self :: from_enum ( ( ty, layout) , * adt_def, cx)
348+ }
349+ ( AdtKind :: Union , Unbounded , Unbounded ) => {
350+ Self :: from_union ( ( ty, layout) , * adt_def, cx)
351+ }
352+ _ => Err ( Err :: NotYetSupported ) ,
353+ }
354+ }
257355
258356 ty:: Ref ( lifetime, ty, mutability) => {
259357 let layout = layout_of ( cx, * ty) ?;
@@ -268,6 +366,10 @@ pub(crate) mod rustc {
268366 } ) )
269367 }
270368
369+ ty:: Char => Ok ( Self :: char ( cx. tcx ( ) . data_layout . endian . into ( ) ) ) ,
370+
371+ ty:: Alias ( _kind, ty) => Self :: from_ty ( ty. to_ty ( cx. tcx ( ) ) , cx) ,
372+
271373 _ => Err ( Err :: NotYetSupported ) ,
272374 }
273375 }
@@ -450,7 +552,7 @@ pub(crate) mod rustc {
450552 & bytes[ bytes. len ( ) - size. bytes_usize ( ) ..]
451553 }
452554 } ;
453- Self :: Seq ( bytes. iter ( ) . map ( |& b| Self :: from_bits ( b) ) . collect ( ) )
555+ Self :: Seq ( bytes. iter ( ) . map ( |& b| Self :: byte ( b) ) . collect ( ) )
454556 }
455557
456558 /// Constructs a `Tree` from a union.
0 commit comments