/// Find the offset of a niche leaf field, starting from
/// the given type and recursing through aggregates.
// FIXME(eddyb) traverse already optimized enums.
Find the offset of a niche leaf field, starting from
the given type and recursing through aggregates.
FIXME(eddyb) traverse already optimized enums.
Find the offset of a niche leaf field starting from the given type and recursing through aggregates . FIXME ( eddyb ) traverse already optimized enums .
fn find_niche(self, layout: TyLayout<'tcx>) -> Result<Option<Niche>, LayoutError<'tcx>> {
        let scalar_niche = |scalar: &Scalar, offset| {
            let Scalar { value, valid_range: ref v } = *scalar;
            let bits = value.size(self).bits();
            assert!(bits <= 128);
            let max_value = !0u128 >> (128 - bits);
            // Find out how many values are outside the valid range.
            let available = if v.start() <= v.end() {
                v.start() + (max_value - v.end())
            } else {
                v.start() - v.end() - 1
            };
            // Give up if there is no niche value available.
            if available == 0 {
                return None;
            }
            Some(Niche { offset, scalar: scalar.clone(), available })
        };
        // Locals variables which live across yields are stored
        // in the generator type as fields. These may be uninitialized
        // so we don't look for niches there.
        if let ty::TyGenerator(..) = layout.ty.sty {
            return Ok(None);
        }
        match layout.abi {
            Abi::Scalar(ref scalar) => {
                return Ok(scalar_niche(scalar, Size::ZERO));
            }
            Abi::ScalarPair(ref a, ref b) => {
                // HACK(nox): We iter on `b` and then `a` because `max_by_key`
                // returns the last maximum.
                let niche = iter::once((b, a.value.size(self).abi_align(b.value.align(self))))
                    .chain(iter::once((a, Size::ZERO)))
                    .filter_map(|(scalar, offset)| scalar_niche(scalar, offset))
                    .max_by_key(|niche| niche.available);
                return Ok(niche);
            }
            Abi::Vector { ref element, .. } => {
                return Ok(scalar_niche(element, Size::ZERO));
            }
            _ => {}
        }
        // Perhaps one of the fields is non-zero, let's recurse and find out.
        if let FieldPlacement::Union(_) = layout.fields {
            // Only Rust enums have safe-to-inspect fields
            // (a discriminant), other unions are unsafe.
            if let Variants::Single { .. } = layout.variants {
                return Ok(None);
            }
        }
        if let FieldPlacement::Array { .. } = layout.fields {
            if layout.fields.count() > 0 {
                return self.find_niche(layout.field(self, 0)?);
            } else {
                return Ok(None);
            }
        }
        let mut niche = None;
        let mut available = 0;
        for i in 0..layout.fields.count() {
            if let Some(mut c) = self.find_niche(layout.field(self, i)?)? {
                if c.available > available {
                    available = c.available;
                    c.offset += layout.fields.offset(i);
                    niche = Some(c);
                }
            }
        }
        Ok(niche)
    }
fn find_niche ( self , layout : TyLayout < ' tcx > ) -> Result < Option < Niche > , LayoutError < ' tcx > > { let scalar_niche = | scalar : & Scalar , offset | { let Scalar { value , valid_range : ref v } = * scalar ; let bits = value . size ( self ) . bits ( ) ; assert ! ( bits 128 ) ; let max_value = ! 0u128 >> ( 128 - bits ) ; // Find out how many values are outside the valid range. let available = if v . start ( ) <= v . end ( ) { v . start ( ) + ( max_value - v . end ( ) ) } else { v . start ( ) - v . end ( ) - 1 } ; // Give up if there is no niche value available. if available == 0 { return None ; } Some ( Niche { offset , scalar : scalar . clone ( ) , available } ) } ; // Locals variables which live across yields are stored // in the generator type as fields. These may be uninitialized // so we don't look for niches there. if let ty :: TyGenerator ( .. ) = layout . ty . sty { return Ok ( None ) ; } match layout . abi { Abi :: Scalar ( ref scalar ) => { return Ok ( scalar_niche ( scalar , Size :: ZERO ) ) ; } Abi :: ScalarPair ( ref a , ref b ) => { // HACK(nox): We iter on `b` and then `a` because `max_by_key` // returns the last maximum. let niche = iter :: once ( ( b , a . value . size ( self ) . abi_align ( b . value . align ( self ) ) ) ) . chain ( iter :: once ( ( a , Size :: ZERO ) ) ) . filter_map ( | ( scalar , offset ) | scalar_niche ( scalar , offset ) ) . max_by_key ( | niche | niche . available ) ; return Ok ( niche ) ; } Abi :: Vector { ref element , .. } => { return Ok ( scalar_niche ( element , Size :: ZERO ) ) ; } _ => { } } // Perhaps one of the fields is non-zero, let's recurse and find out. if let FieldPlacement :: Union ( _ ) = layout . fields { // Only Rust enums have safe-to-inspect fields // (a discriminant), other unions are unsafe. if let Variants :: Single { .. } = layout . variants { return Ok ( None ) ; } } if let FieldPlacement :: Array { .. } = layout . fields { if layout . fields . count ( ) > 0 { return self . find_niche ( layout . field ( self , 0 ) ? ) ; } else { return Ok ( None ) ; } } let mut niche = None ; let mut available = 0 ; for i in 0 .. layout . fields . count ( ) { if let Some ( mut c ) = self . find_niche ( layout . field ( self , i ) ? ) ? { if c . available > available { available = c . available ; c . offset += layout . fields . offset ( i ) ; niche = Some ( c ) ; } } } Ok ( niche ) }
Find the offset of a niche leaf field, starting from
the given type and recursing through aggregates.
Find the offset of a niche leaf field starting from the given type and recursing through aggregates .
self
layout
TyLayout<'tcx>