<commit_before>//! This module specifies the type based interner for constants.
//!
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.

use rustc::ty::{Ty, TyCtxt, ParamEnv, self};
use rustc::mir::interpret::{
    InterpResult, ErrorHandled,
};
use rustc::hir;
use rustc::hir::def_id::DefId;
use super::validity::RefTracking;
use rustc_data_structures::fx::FxHashSet;

use syntax::ast::Mutability;
use syntax_pos::Span;

use super::{
    ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, InterpError, Scalar,
};
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};

struct InternVisitor<'rt, 'mir, 'tcx> {
    /// previously encountered safe references
    ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
    ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
    param_env: ParamEnv<'tcx>,
    /// The root node of the value that we're looking at. This field is never mutated and only used
    /// for sanity assertions that will ICE when `const_qualif` screws up.
    mode: InternMode,
    /// This field stores the mutability of the value *currently* being checked.
    /// It is set to mutable when an `UnsafeCell` is encountered
    /// When recursing across a reference, we don't recurse but store the
    /// value to be checked in `ref_tracking` together with the mutability at which we are checking
    /// the value.
    /// When encountering an immutable reference, we treat everything as immutable that is behind
    /// it.
    mutability: Mutability,
    /// A list of all encountered relocations. After type-based interning, we traverse this list to
    /// also intern allocations that are only referenced by a raw pointer or inside a union.
    leftover_relocations: &'rt mut FxHashSet<AllocId>,
}

#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
enum InternMode {
    /// Mutable references must in fact be immutable due to their surrounding immutability in a
    /// `static`. In a `static mut` we start out as mutable and thus can also contain further `&mut`
    /// that will actually be treated as mutable.
    Static,
    /// UnsafeCell is OK in the value of a constant, but not behind references in a constant
    ConstBase,
    /// `UnsafeCell` ICEs
    Const,
}

/// Signalling data structure to ensure we don't recurse
/// into the memory of other constants or statics
struct IsStaticOrFn;

impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> {
    /// Intern an allocation without looking at its children
    fn intern_shallow(
        &mut self,
        ptr: Pointer,
        mutability: Mutability,
    ) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
        trace!(
            "InternVisitor::intern {:?} with {:?}",
            ptr, mutability,
        );
        // remove allocation
        let tcx = self.ecx.tcx;
        let memory = self.ecx.memory_mut();
        let (kind, mut alloc) = match memory.alloc_map.remove(&ptr.alloc_id) {
            Some(entry) => entry,
            None => {
                // if the pointer is dangling (neither in local nor global memory), we leave it
                // to validation to error. The `delay_span_bug` ensures that we don't forget such
                // a check in validation.
                if tcx.alloc_map.lock().get(ptr.alloc_id).is_none() {
                    tcx.sess.delay_span_bug(self.ecx.tcx.span, "tried to intern dangling pointer");
                }
                // treat dangling pointers like other statics
                // just to stop trying to recurse into them
                return Ok(Some(IsStaticOrFn));
            },
        };
        // This match is just a canary for future changes to `MemoryKind`, which most likely need
        // changes in this function.
        match kind {
            MemoryKind::Stack | MemoryKind::Vtable => {},
        }
        // Ensure llvm knows to only put this into immutable memory if the value is immutable either
        // by being behind a reference or by being part of a static or const without interior
        // mutability
        alloc.mutability = mutability;
        // link the alloc id to the actual allocation
        let alloc = tcx.intern_const_alloc(alloc);
        self.leftover_relocations.extend(alloc.relocations.iter().map(|&(_, ((), reloc))| reloc));
        tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc);
        Ok(None)
    }
}

impl<'rt, 'mir, 'tcx>
    ValueVisitor<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>
for
    InternVisitor<'rt, 'mir, 'tcx>
{
    type V = MPlaceTy<'tcx>;

    #[inline(always)]
    fn ecx(&self) -> &CompileTimeEvalContext<'mir, 'tcx> {
        &self.ecx
    }

    fn visit_aggregate(
        &mut self,
        mplace: MPlaceTy<'tcx>,
        fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
    ) -> InterpResult<'tcx> {
        if let Some(def) = mplace.layout.ty.ty_adt_def() {
            if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
                // We are crossing over an `UnsafeCell`, we can mutate again
                let old = std::mem::replace(&mut self.mutability, Mutability::Mutable);
                assert_ne!(
                    self.mode, InternMode::Const,
                    "UnsafeCells are not allowed behind references in constants. This should have \
                    been prevented statically by const qualification. If this were allowed one \
                    would be able to change a constant at one use site and other use sites may \
                    arbitrarily decide to change, too.",
                );
                let walked = self.walk_aggregate(mplace, fields);
                self.mutability = old;
                return walked;
            }
        }
        self.walk_aggregate(mplace, fields)
    }

    fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
        // Handle Reference types, as these are the only relocations supported by const eval.
        // Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
        let ty = mplace.layout.ty;
        if let ty::Ref(_, referenced_ty, mutability) = ty.sty {
            let value = self.ecx.read_immediate(mplace.into())?;
            // Handle trait object vtables
            if let Ok(meta) = value.to_meta() {
                if let ty::Dynamic(..) = self.ecx.tcx.struct_tail(referenced_ty).sty {
                        if let Ok(vtable) = meta.unwrap().to_ptr() {
                            // explitly choose `Immutable` here, since vtables are immutable, even
                            // if the reference of the fat pointer is mutable
                            self.intern_shallow(vtable, Mutability::Immutable)?;
                        }
                    }
                }
            let mplace = self.ecx.ref_to_mplace(value)?;
            // Check if we have encountered this pointer+layout combination before.
            // Only recurse for allocation-backed pointers.
            if let Scalar::Ptr(ptr) = mplace.ptr {
                // We do not have any `frozen` logic here, because it's essentially equivalent to
                // the mutability except for the outermost item. Only `UnsafeCell` can "unfreeze",
                // and we check that in `visit_aggregate`.
                // This is not an inherent limitation, but one that we know to be true, because
                // const qualification enforces it. We can lift it in the future.
                match (self.mode, mutability) {
                    // immutable references are fine everywhere
                    (_, hir::Mutability::MutImmutable) => {},
                    // all is "good and well" in the unsoundness of `static mut`

                    // mutable references are ok in `static`. Either they are treated as immutable
                    // because they are behind an immutable one, or they are behind an `UnsafeCell`
                    // and thus ok.
                    (InternMode::Static, hir::Mutability::MutMutable) => {},
                    // we statically prevent `&mut T` via `const_qualif` and double check this here
                    (InternMode::ConstBase, hir::Mutability::MutMutable) |
                    (InternMode::Const, hir::Mutability::MutMutable) =>
                        bug!("const qualif failed to prevent mutable references"),
                }
                // Compute the mutability with which we'll start visiting the allocation. This is
                // what gets changed when we encounter an `UnsafeCell`
                let mutability = match (self.mutability, mutability) {
                    // The only way a mutable reference actually works as a mutable reference is
                    // by being in a `static mut` directly or behind another mutable reference.
                    // If there's an immutable reference or we are inside a static, then our
                    // mutable reference is equivalent to an immutable one. As an example:
                    // `&&mut Foo` is semantically equivalent to `&&Foo`
                    (Mutability::Mutable, hir::Mutability::MutMutable) => Mutability::Mutable,
                    _ => Mutability::Immutable,
                };
                // Compute the mutability of the allocation
                let intern_mutability = intern_mutability(
                    self.ecx.tcx.tcx,
                    self.param_env,
                    mplace.layout.ty,
                    self.ecx.tcx.span,
                    mutability,
                );
                // Recursing behind references changes the intern mode for constants in order to
                // cause assertions to trigger if we encounter any `UnsafeCell`s.
                let mode = match self.mode {
                    InternMode::ConstBase => InternMode::Const,
                    other => other,
                };
                match self.intern_shallow(ptr, intern_mutability)? {
                    // No need to recurse, these are interned already and statics may have
                    // cycles, so we don't want to recurse there
                    Some(IsStaticOrFn) => {},
                    // intern everything referenced by this value. The mutability is taken from the
                    // reference. It is checked above that mutable references only happen in
                    // `static mut`
                    None => self.ref_tracking.track((mplace, mutability, mode), || ()),
                }
            }
        }
        Ok(())
    }
}

/// Figure out the mutability of the allocation.
/// Mutable if it has interior mutability *anywhere* in the type.
fn intern_mutability<'tcx>(
    tcx: TyCtxt<'tcx>,
    param_env: ParamEnv<'tcx>,
    ty: Ty<'tcx>,
    span: Span,
    mutability: Mutability,
) -> Mutability {
    let has_interior_mutability = !ty.is_freeze(tcx, param_env, span);
    if has_interior_mutability {
        Mutability::Mutable
    } else {
        mutability
    }
}

pub fn intern_const_alloc_recursive(
    ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
    def_id: DefId,
    ret: MPlaceTy<'tcx>,
    // FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval
    // must always be monomorphic, right?
    param_env: ty::ParamEnv<'tcx>,
) -> InterpResult<'tcx> {
    let tcx = ecx.tcx;
    // this `mutability` is the mutability of the place, ignoring the type
    let (mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
        Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static),
        None => (Mutability::Immutable, InternMode::ConstBase),
        // `static mut` doesn't care about interior mutability, it's mutable anyway
        Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::Static),
    };

    // type based interning
    let mut ref_tracking = RefTracking::new((ret, mutability, base_intern_mode));
    let leftover_relocations = &mut FxHashSet::default();

    // This mutability is the combination of the place mutability and the type mutability. If either
    // is mutable, `alloc_mutability` is mutable. This exists because the entire allocation needs
    // to be mutable if it contains an `UnsafeCell` anywhere. The other `mutability` exists so that
    // the visitor does not treat everything outside the `UnsafeCell` as mutable.
    let alloc_mutability = intern_mutability(
        tcx.tcx, param_env, ret.layout.ty, tcx.span, mutability,
    );

    // start with the outermost allocation
    InternVisitor {
        ref_tracking: &mut ref_tracking,
        ecx,
        mode: base_intern_mode,
        leftover_relocations,
        param_env,
        mutability,
    }.intern_shallow(ret.ptr.to_ptr()?, alloc_mutability)?;

    while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() {
        let interned = InternVisitor {
            ref_tracking: &mut ref_tracking,
            ecx,
            mode,
            leftover_relocations,
            param_env,
            mutability,
        }.visit_value(mplace);
        if let Err(error) = interned {
            // This can happen when e.g. the tag of an enum is not a valid discriminant. We do have
            // to read enum discriminants in order to find references in enum variant fields.
            if let InterpError::ValidationFailure(_) = error.kind {
                let err = crate::const_eval::error_to_const_error(&ecx, error);
                match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
                    Ok(mut diag) => {
                        diag.note("The rules on what exactly is undefined behavior aren't clear, \
                            so this check might be overzealous. Please open an issue on the rust \
                            compiler repository if you believe it should not be considered \
                            undefined behavior",
                        );
                        diag.emit();
                    }
                    Err(ErrorHandled::TooGeneric) |
                    Err(ErrorHandled::Reported) => {},
                }
            }
        }
    }

    // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw
    // pointers, ... So we can't intern them according to their type rules

    let mut todo: Vec<_> = leftover_relocations.iter().cloned().collect();
    while let Some(alloc_id) = todo.pop() {
        if let Some((_, alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
            // We can't call the `intern` method here, as its logic is tailored to safe references.
            // So we hand-roll the interning logic here again
            let alloc = tcx.intern_const_alloc(alloc);
            tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc);
            for &(_, ((), reloc)) in alloc.relocations.iter() {
                if leftover_relocations.insert(reloc) {
                    todo.push(reloc);
                }
            }
        } else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) {
            // dangling pointer
            return err!(ValidationFailure(
                "encountered dangling pointer in final constant".into(),
            ))
        }
    }
    Ok(())
}
<commit_msg>Don't ICE on mutable zst slices<commit_after>//! This module specifies the type based interner for constants.
//!
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.

use rustc::ty::{Ty, TyCtxt, ParamEnv, self};
use rustc::mir::interpret::{
    InterpResult, ErrorHandled,
};
use rustc::hir;
use rustc::hir::def_id::DefId;
use super::validity::RefTracking;
use rustc_data_structures::fx::FxHashSet;

use syntax::ast::Mutability;
use syntax_pos::Span;

use super::{
    ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, InterpError, Scalar,
};
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};

struct InternVisitor<'rt, 'mir, 'tcx> {
    /// previously encountered safe references
    ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
    ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
    param_env: ParamEnv<'tcx>,
    /// The root node of the value that we're looking at. This field is never mutated and only used
    /// for sanity assertions that will ICE when `const_qualif` screws up.
    mode: InternMode,
    /// This field stores the mutability of the value *currently* being checked.
    /// It is set to mutable when an `UnsafeCell` is encountered
    /// When recursing across a reference, we don't recurse but store the
    /// value to be checked in `ref_tracking` together with the mutability at which we are checking
    /// the value.
    /// When encountering an immutable reference, we treat everything as immutable that is behind
    /// it.
    mutability: Mutability,
    /// A list of all encountered relocations. After type-based interning, we traverse this list to
    /// also intern allocations that are only referenced by a raw pointer or inside a union.
    leftover_relocations: &'rt mut FxHashSet<AllocId>,
}

#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
enum InternMode {
    /// Mutable references must in fact be immutable due to their surrounding immutability in a
    /// `static`. In a `static mut` we start out as mutable and thus can also contain further `&mut`
    /// that will actually be treated as mutable.
    Static,
    /// UnsafeCell is OK in the value of a constant, but not behind references in a constant
    ConstBase,
    /// `UnsafeCell` ICEs
    Const,
}

/// Signalling data structure to ensure we don't recurse
/// into the memory of other constants or statics
struct IsStaticOrFn;

impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> {
    /// Intern an allocation without looking at its children
    fn intern_shallow(
        &mut self,
        ptr: Pointer,
        mutability: Mutability,
    ) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
        trace!(
            "InternVisitor::intern {:?} with {:?}",
            ptr, mutability,
        );
        // remove allocation
        let tcx = self.ecx.tcx;
        let memory = self.ecx.memory_mut();
        let (kind, mut alloc) = match memory.alloc_map.remove(&ptr.alloc_id) {
            Some(entry) => entry,
            None => {
                // if the pointer is dangling (neither in local nor global memory), we leave it
                // to validation to error. The `delay_span_bug` ensures that we don't forget such
                // a check in validation.
                if tcx.alloc_map.lock().get(ptr.alloc_id).is_none() {
                    tcx.sess.delay_span_bug(self.ecx.tcx.span, "tried to intern dangling pointer");
                }
                // treat dangling pointers like other statics
                // just to stop trying to recurse into them
                return Ok(Some(IsStaticOrFn));
            },
        };
        // This match is just a canary for future changes to `MemoryKind`, which most likely need
        // changes in this function.
        match kind {
            MemoryKind::Stack | MemoryKind::Vtable => {},
        }
        // Ensure llvm knows to only put this into immutable memory if the value is immutable either
        // by being behind a reference or by being part of a static or const without interior
        // mutability
        alloc.mutability = mutability;
        // link the alloc id to the actual allocation
        let alloc = tcx.intern_const_alloc(alloc);
        self.leftover_relocations.extend(alloc.relocations.iter().map(|&(_, ((), reloc))| reloc));
        tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc);
        Ok(None)
    }
}

impl<'rt, 'mir, 'tcx>
    ValueVisitor<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>
for
    InternVisitor<'rt, 'mir, 'tcx>
{
    type V = MPlaceTy<'tcx>;

    #[inline(always)]
    fn ecx(&self) -> &CompileTimeEvalContext<'mir, 'tcx> {
        &self.ecx
    }

    fn visit_aggregate(
        &mut self,
        mplace: MPlaceTy<'tcx>,
        fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
    ) -> InterpResult<'tcx> {
        if let Some(def) = mplace.layout.ty.ty_adt_def() {
            if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
                // We are crossing over an `UnsafeCell`, we can mutate again
                let old = std::mem::replace(&mut self.mutability, Mutability::Mutable);
                assert_ne!(
                    self.mode, InternMode::Const,
                    "UnsafeCells are not allowed behind references in constants. This should have \
                    been prevented statically by const qualification. If this were allowed one \
                    would be able to change a constant at one use site and other use sites may \
                    arbitrarily decide to change, too.",
                );
                let walked = self.walk_aggregate(mplace, fields);
                self.mutability = old;
                return walked;
            }
        }
        self.walk_aggregate(mplace, fields)
    }

    fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
        // Handle Reference types, as these are the only relocations supported by const eval.
        // Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
        let ty = mplace.layout.ty;
        if let ty::Ref(_, referenced_ty, mutability) = ty.sty {
            let value = self.ecx.read_immediate(mplace.into())?;
            // Handle trait object vtables
            if let Ok(meta) = value.to_meta() {
                if let ty::Dynamic(..) = self.ecx.tcx.struct_tail(referenced_ty).sty {
                    if let Ok(vtable) = meta.unwrap().to_ptr() {
                        // explitly choose `Immutable` here, since vtables are immutable, even
                        // if the reference of the fat pointer is mutable
                        self.intern_shallow(vtable, Mutability::Immutable)?;
                    }
                }
            }
            let mplace = self.ecx.ref_to_mplace(value)?;
            // Check if we have encountered this pointer+layout combination before.
            // Only recurse for allocation-backed pointers.
            if let Scalar::Ptr(ptr) = mplace.ptr {
                // We do not have any `frozen` logic here, because it's essentially equivalent to
                // the mutability except for the outermost item. Only `UnsafeCell` can "unfreeze",
                // and we check that in `visit_aggregate`.
                // This is not an inherent limitation, but one that we know to be true, because
                // const qualification enforces it. We can lift it in the future.
                match (self.mode, mutability) {
                    // immutable references are fine everywhere
                    (_, hir::Mutability::MutImmutable) => {},
                    // all is "good and well" in the unsoundness of `static mut`

                    // mutable references are ok in `static`. Either they are treated as immutable
                    // because they are behind an immutable one, or they are behind an `UnsafeCell`
                    // and thus ok.
                    (InternMode::Static, hir::Mutability::MutMutable) => {},
                    // we statically prevent `&mut T` via `const_qualif` and double check this here
                    (InternMode::ConstBase, hir::Mutability::MutMutable) |
                    (InternMode::Const, hir::Mutability::MutMutable) => {
                        match referenced_ty.sty {
                            ty::Array(_, n) if n.unwrap_usize(self.ecx.tcx.tcx) == 0 => {}
                            ty::Slice(_)
                                if value.to_meta().unwrap().unwrap().to_usize(self.ecx)? == 0 => {}
                            _ => bug!("const qualif failed to prevent mutable references"),
                        }
                    },
                }
                // Compute the mutability with which we'll start visiting the allocation. This is
                // what gets changed when we encounter an `UnsafeCell`
                let mutability = match (self.mutability, mutability) {
                    // The only way a mutable reference actually works as a mutable reference is
                    // by being in a `static mut` directly or behind another mutable reference.
                    // If there's an immutable reference or we are inside a static, then our
                    // mutable reference is equivalent to an immutable one. As an example:
                    // `&&mut Foo` is semantically equivalent to `&&Foo`
                    (Mutability::Mutable, hir::Mutability::MutMutable) => Mutability::Mutable,
                    _ => Mutability::Immutable,
                };
                // Compute the mutability of the allocation
                let intern_mutability = intern_mutability(
                    self.ecx.tcx.tcx,
                    self.param_env,
                    mplace.layout.ty,
                    self.ecx.tcx.span,
                    mutability,
                );
                // Recursing behind references changes the intern mode for constants in order to
                // cause assertions to trigger if we encounter any `UnsafeCell`s.
                let mode = match self.mode {
                    InternMode::ConstBase => InternMode::Const,
                    other => other,
                };
                match self.intern_shallow(ptr, intern_mutability)? {
                    // No need to recurse, these are interned already and statics may have
                    // cycles, so we don't want to recurse there
                    Some(IsStaticOrFn) => {},
                    // intern everything referenced by this value. The mutability is taken from the
                    // reference. It is checked above that mutable references only happen in
                    // `static mut`
                    None => self.ref_tracking.track((mplace, mutability, mode), || ()),
                }
            }
        }
        Ok(())
    }
}

/// Figure out the mutability of the allocation.
/// Mutable if it has interior mutability *anywhere* in the type.
fn intern_mutability<'tcx>(
    tcx: TyCtxt<'tcx>,
    param_env: ParamEnv<'tcx>,
    ty: Ty<'tcx>,
    span: Span,
    mutability: Mutability,
) -> Mutability {
    let has_interior_mutability = !ty.is_freeze(tcx, param_env, span);
    if has_interior_mutability {
        Mutability::Mutable
    } else {
        mutability
    }
}

pub fn intern_const_alloc_recursive(
    ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
    def_id: DefId,
    ret: MPlaceTy<'tcx>,
    // FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval
    // must always be monomorphic, right?
    param_env: ty::ParamEnv<'tcx>,
) -> InterpResult<'tcx> {
    let tcx = ecx.tcx;
    // this `mutability` is the mutability of the place, ignoring the type
    let (mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
        Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static),
        None => (Mutability::Immutable, InternMode::ConstBase),
        // `static mut` doesn't care about interior mutability, it's mutable anyway
        Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::Static),
    };

    // type based interning
    let mut ref_tracking = RefTracking::new((ret, mutability, base_intern_mode));
    let leftover_relocations = &mut FxHashSet::default();

    // This mutability is the combination of the place mutability and the type mutability. If either
    // is mutable, `alloc_mutability` is mutable. This exists because the entire allocation needs
    // to be mutable if it contains an `UnsafeCell` anywhere. The other `mutability` exists so that
    // the visitor does not treat everything outside the `UnsafeCell` as mutable.
    let alloc_mutability = intern_mutability(
        tcx.tcx, param_env, ret.layout.ty, tcx.span, mutability,
    );

    // start with the outermost allocation
    InternVisitor {
        ref_tracking: &mut ref_tracking,
        ecx,
        mode: base_intern_mode,
        leftover_relocations,
        param_env,
        mutability,
    }.intern_shallow(ret.ptr.to_ptr()?, alloc_mutability)?;

    while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() {
        let interned = InternVisitor {
            ref_tracking: &mut ref_tracking,
            ecx,
            mode,
            leftover_relocations,
            param_env,
            mutability,
        }.visit_value(mplace);
        if let Err(error) = interned {
            // This can happen when e.g. the tag of an enum is not a valid discriminant. We do have
            // to read enum discriminants in order to find references in enum variant fields.
            if let InterpError::ValidationFailure(_) = error.kind {
                let err = crate::const_eval::error_to_const_error(&ecx, error);
                match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
                    Ok(mut diag) => {
                        diag.note("The rules on what exactly is undefined behavior aren't clear, \
                            so this check might be overzealous. Please open an issue on the rust \
                            compiler repository if you believe it should not be considered \
                            undefined behavior",
                        );
                        diag.emit();
                    }
                    Err(ErrorHandled::TooGeneric) |
                    Err(ErrorHandled::Reported) => {},
                }
            }
        }
    }

    // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw
    // pointers, ... So we can't intern them according to their type rules

    let mut todo: Vec<_> = leftover_relocations.iter().cloned().collect();
    while let Some(alloc_id) = todo.pop() {
        if let Some((_, alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
            // We can't call the `intern` method here, as its logic is tailored to safe references.
            // So we hand-roll the interning logic here again
            let alloc = tcx.intern_const_alloc(alloc);
            tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc);
            for &(_, ((), reloc)) in alloc.relocations.iter() {
                if leftover_relocations.insert(reloc) {
                    todo.push(reloc);
                }
            }
        } else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) {
            // dangling pointer
            return err!(ValidationFailure(
                "encountered dangling pointer in final constant".into(),
            ))
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(compiler_builtins)]
#![no_std]
#![compiler_builtins]
#![unstable(feature = "compiler_builtins_lib",
            reason = "internal implementation detail of rustc right now",
            issue = "0")]
#![crate_name = "compiler_builtins"]
#![crate_type = "rlib"]
#![feature(staged_api)]
<commit_msg>WIP intrinsics<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(compiler_builtins)]
#![no_std]
#![compiler_builtins]
#![unstable(feature = "compiler_builtins_lib",
            reason = "internal implementation detail of rustc right now",
            issue = "0")]
#![crate_name = "compiler_builtins"]
#![crate_type = "rlib"]
#![feature(staged_api)]
#![feature(core_intrinsics)]
#![feature(core_float)]
#![feature(associated_consts)]
#![cfg_attr(not(stage0), feature(i128_type))]

#![allow(non_camel_case_types, unused_variables)]

#[cfg(any(target_pointer_width="32", target_pointer_width="16"))]
pub mod reimpls {
    #![allow(unused_comparisons)]
    // C API is expected to tolerate some amount of size mismatch in ABI. Hopefully the amount of
    // handling is sufficient for bootstrapping.
    #[cfg(stage0)]
    type u128_ = u64;
    #[cfg(stage0)]
    type i128_ = i64;
    #[cfg(not(stage0))]
    type u128_ = u128;
    #[cfg(not(stage0))]
    type i128_ = i128;

    fn unimplemented() -> ! {
        unsafe { ::core::intrinsics::abort() }
    }

    macro_rules! ashl {
        ($a:expr, $b:expr, $ty:ty) => {{
            let (a, b) = ($a, $b);
            let bits = (::core::mem::size_of::<$ty>() * 8) as $ty;
            let half_bits = bits / 2;
            if b & half_bits != 0 {
                <$ty>::from_parts(0, a.low() << (b - half_bits))
            } else if b == 0 {
                a
            } else {
                <$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b)))
            }
        }}
    }

    #[export_name="__ashlti3"]
    pub extern fn shl(a: u128_, b: u128_) -> u128_ {
        ashl!(a, b, u128_)
    }

    macro_rules! ashr {
        ($a: expr, $b: expr, $ty:ty) => {{
            let (a, b) = ($a, $b);
            let bits = (::core::mem::size_of::<$ty>() * 8) as $ty;
            let half_bits = bits / 2;
            if b & half_bits != 0 {
                <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf,
                                  a.high() >> (half_bits - 1))
            } else if b == 0 {
                a
            } else {
                let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf;
                <$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b),
                                  a.high() >> b)
            }
        }}
    }

    #[export_name="__ashrti3"]
    pub extern fn shr(a: i128_, b: i128_) -> i128_ {
        ashr!(a, b, i128_)
    }

    macro_rules! lshr {
        ($a: expr, $b: expr, $ty:ty) => {{
            let (a, b) = ($a, $b);
            let bits = (::core::mem::size_of::<$ty>() * 8) as $ty;
            let half_bits = bits / 2;
            if b & half_bits != 0 {
                <$ty>::from_parts(a.high() >> (b - half_bits), 0)
            } else if b == 0 {
                a
            } else {
                <$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b)
            }
        }}
    }

    #[export_name="__lshrti3"]
    pub extern fn lshr(a: u128_, b: u128_) -> u128_ {
        lshr!(a, b, u128_)
    }

    #[cfg(stage0)]
    #[export_name="__udivmodti4"]
    pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ {
        unsafe {
        if !rem.is_null() {
            *rem = n % d;
        }
        n / d
        }
    }

    #[cfg(not(stage0))]
    #[export_name="__udivmodti4"]
    pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ {
        unsafe {
        // NOTE X is unknown, K != 0
        if n.high() == 0 {
            if d.high() == 0 {
                // 0 X
                // ---
                // 0 X
                if !rem.is_null() {
                    *rem = u128::from(n.low() % d.low());
                }
                return u128::from(n.low() / d.low());
            } else {
                // 0 X
                // ---
                // K X
                if !rem.is_null() {
                    *rem = n;
                }
                return 0;
            };
        }

        let mut sr;
        let mut q;
        let mut r;

        if d.low() == 0 {
            if d.high() == 0 {
                // K X
                // ---
                // 0 0
                unimplemented()
            }

            if n.low() == 0 {
                // K 0
                // ---
                // K 0
                if !rem.is_null() {
                    *rem = u128::from_parts(0, n.high() % d.high());
                }
                return u128::from(n.high() / d.high());
            }

            // K K
            // ---
            // K 0

            if d.high().is_power_of_two() {
                if !rem.is_null() {
                    *rem = u128::from_parts(n.low(), n.high() & (d.high() - 1));
                }
                return u128::from(n.high() >> d.high().trailing_zeros());
            }

            sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());

            // D > N
            if sr > 64 - 2 {
                if !rem.is_null() {
                    *rem = n;
                }
                return 0;
            }

            sr += 1;

            // 1 <= sr <= u32::bits() - 1
            q = n << (128 - sr);
            r = n >> sr;
        } else {
            if d.high() == 0 {
                // K X
                // ---
                // 0 K
                if d.low().is_power_of_two() {
                    if !rem.is_null() {
                        *rem = u128::from(n.low() & (d.low() - 1));
                    }

                    if d.low() == 1 {
                        return n;
                    } else {
                        let sr = d.low().trailing_zeros();
                        return n >> sr;
                    };
                }

                sr = 1 + 64 + d.low().leading_zeros() - n.high().leading_zeros();

                // 2 <= sr <= u64::bits() - 1
                q = n << (128 - sr);
                r = n >> sr;
            } else {
                // K X
                // ---
                // K K
                sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros());

                // D > N
                if sr > 64 - 1 {
                    if !rem.is_null() {
                        *rem = n;
                    }
                    return 0;
                }

                sr += 1;

                // 1 <= sr <= u32::bits()
                q = n << (128 - sr);
                r = n >> sr;
            }
        }

        // Not a special case
        // q and r are initialized with
        // q = n << (u64::bits() - sr)
        // r = n >> sr
        // 1 <= sr <= u64::bits() - 1
        let mut carry = 0;

        for _ in 0..sr {
            // r:q = ((r:q) << 1) | carry
            r = (r << 1) | (q >> (128 - 1));
            q = (q << 1) | carry as u128;

            // carry = 0
            // if r >= d {
            //     r -= d;
            //     carry = 1;
            // }
            let s = (d.wrapping_sub(r).wrapping_sub(1)) as i128 >> (128 - 1);
            carry = (s & 1) as u64;
            r -= d & s as u128;
        }

        if !rem.is_null() {
            *rem = r;
        }
        (q << 1) | carry as u128
        }
    }

    #[export_name="__umodti3"]
    pub extern fn u128_mod(a: u128_, b: u128_) -> u128_ {
        unsafe {
            let mut r = ::core::mem::zeroed();
            u128_div_mod(a, b, &mut r);
            r
        }
    }

    #[export_name="__modti3"]
    pub extern fn i128_mod(a: i128_, b: i128_) -> i128_ {
        let b = b.abs();
        let sa = a.signum();
        let a = a.abs();
        unsafe {
            let mut r = ::core::mem::zeroed();
            u128_div_mod(a as u128_, b as u128_, &mut r);
            if sa == -1 { -(r as i128_) } else { r as i128_ }
        }
    }

    #[export_name="__divti3"]
    pub extern fn i128_div(a: i128_, b: i128_) -> i128_ {
        let sa = a.signum();
        let sb = b.signum();
        let a = a.abs();
        let b = b.abs();
        let sr = sa ^ sb;
        unsafe {
            let mut r = ::core::mem::zeroed();
            if sa == -1 {
                -(u128_div_mod(a as u128_, b as u128_, &mut r) as i128_)
            } else {
                u128_div_mod(a as u128_, b as u128_, &mut r) as i128_
            }
        }
    }

    #[export_name="__udivti3"]
    pub extern fn u128_div(a: u128_, b: u128_) -> u128_ {
        unsafe {
            let mut r = ::core::mem::zeroed();
            u128_div_mod(a, b, &mut r)
        }
    }

    macro_rules! mulo {
        ($a:expr, $b:expr, $o: expr, $ty: ty) => {{
            let (a, b, overflow) = ($a, $b, $o);
            *overflow = 0;
            let result = a.wrapping_mul(b);
            if a == <$ty>::min_value() {
                if b != 0 && b != 1 {
                    *overflow = 1;
                }
                return result;
            }
            if b == <$ty>::min_value() {
                if a != 0 && a != 1 {
                    *overflow = 1;
                }
                return result;
            }

            let bits = ::core::mem::size_of::<$ty>() * 8;
            let sa = a >> (bits - 1);
            let abs_a = (a ^ sa) - sa;
            let sb = b >> (bits - 1);
            let abs_b = (b ^ sb) - sb;
            if abs_a < 2 || abs_b < 2 {
                return result;
            }
            if sa == sb {
                if abs_a > <$ty>::max_value() / abs_b {
                    *overflow = 1;
                }
            } else {
                if abs_a > <$ty>::min_value() / -abs_b {
                    *overflow = 1;
                }
            }
            result
        }}
    }

    // FIXME: i32 here should be c_int.
    #[export_name="__muloti4"]
    pub extern fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128_ {
        if let Some(v) = (a as i64).checked_mul(b as i64) {
            *o = 0;
            v as i128_
        } else {
            *o = 1;
            0
        }
    }

    pub trait LargeInt {
        type LowHalf;
        type HighHalf;

        fn low(self) -> Self::LowHalf;
        fn high(self) -> Self::HighHalf;
        fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self;
    }
    impl LargeInt for u64 {
        type LowHalf = u32;
        type HighHalf = u32;

        fn low(self) -> u32 {
            self as u32
        }
        fn high(self) -> u32 {
            (self >> 32) as u32
        }
        fn from_parts(low: u32, high: u32) -> u64 {
            low as u64 | ((high as u64) << 32)
        }
    }
    impl LargeInt for i64 {
        type LowHalf = u32;
        type HighHalf = i32;

        fn low(self) -> u32 {
            self as u32
        }
        fn high(self) -> i32 {
            (self >> 32) as i32
        }
        fn from_parts(low: u32, high: i32) -> i64 {
            low as i64 | ((high as i64) << 32)
        }
    }
    #[cfg(not(stage0))]
    impl LargeInt for u128 {
        type LowHalf = u64;
        type HighHalf = u64;

        fn low(self) -> u64 {
            self as u64
        }
        fn high(self) -> u64 {
            unsafe { *(&self as *const u128 as *const u64) }
        }
        fn from_parts(low: u64, high: u64) -> u128 {
            #[repr(C, packed)] struct Parts(u64, u64);
            unsafe { ::core::mem::transmute(Parts(low, high)) }
        }
    }
    #[cfg(not(stage0))]
    impl LargeInt for i128 {
        type LowHalf = u64;
        type HighHalf = i64;

        fn low(self) -> u64 {
            self as u64
        }
        fn high(self) -> i64 {
            unsafe { *(&self as *const i128 as *const i64) }
        }
        fn from_parts(low: u64, high: i64) -> i128 {
            u128::from_parts(low, high as u64) as i128
        }
    }

    macro_rules! mul {
        ($a:expr, $b:expr, $ty: ty) => {{
            let (a, b) = ($a, $b);
            let bits = ::core::mem::size_of::<$ty>() * 8;
            let half_bits = bits / 4;
            let lower_mask = !0 >> half_bits;
            let mut low = (a.low() & lower_mask) * (b.low() & lower_mask);
            let mut t = low >> half_bits;
            low &= lower_mask;
            t += (a.low() >> half_bits) * (b.low() & lower_mask);
            low += (t & lower_mask) << half_bits;
            let mut high = t >> half_bits;
            t = low >> half_bits;
            low &= lower_mask;
            t += (b.low() >> half_bits) * (a.low() & lower_mask);
            low += (t & lower_mask) << half_bits;
            high += t >> half_bits;
            high += (a.low() >> half_bits) * (b.low() >> half_bits);
            high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high())));
            <$ty>::from_parts(low, high)
        }}
    }

    #[export_name="__multi3"]
    pub extern fn u128_mul(a: u128_, b: u128_) -> u128_ {
        (a as u64 * b as u64) as u128_
        // mul!(a, b, u128_)
    }

    trait FloatStuff: Sized {
        type ToBytes;

        const MANTISSA_BITS: u32;
        const MAX_EXP: i32;
        const EXP_MASK: Self::ToBytes;
        const MANTISSA_MASK: Self::ToBytes;

        fn to_bytes(self) -> Self::ToBytes;
        fn get_exponent(self) -> i32;
    }

    impl FloatStuff for f32 {
        type ToBytes = u32;
        const MANTISSA_BITS: u32 = 23;
        const MAX_EXP: i32 = 127;
        const MANTISSA_MASK: u32 = 0x007F_FFFF;
        const EXP_MASK: u32 = 0x7F80_0000;

        fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } }
        fn get_exponent(self) -> i32 {
            (((self.to_bytes() & Self::EXP_MASK) >> Self::MANTISSA_BITS) as i32) - Self::MAX_EXP
        }
    }

    impl FloatStuff for f64 {
        type ToBytes = u64;
        const MANTISSA_BITS: u32 = 52;
        const MAX_EXP: i32 = 1023;
        const EXP_MASK: u64 = 0x7FF0_0000_0000_0000;
        const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF;

        fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } }
        fn get_exponent(self) -> i32 {
            (((self.to_bytes() & Self::EXP_MASK) >> Self::MANTISSA_BITS) as i32) - Self::MAX_EXP
        }
    }

    macro_rules! float_as_unsigned {
        ($from: expr, $fromty: ty, $outty: ty) => { {
            use core::num::Float;
            let repr = $from.to_bytes();
            let sign = $from.signum();
            let exponent = $from.get_exponent();
            let mantissa = repr & <$fromty as FloatStuff>::MANTISSA_MASK;
            if sign == -1.0 || exponent < 0 { return 0; }
            if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 {
                return !0;
            }
            if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
                mantissa as $outty >> (<$fromty as FloatStuff>::MANTISSA_BITS as i32 - exponent)
            } else {
                mantissa as $outty << (exponent - <$fromty as FloatStuff>::MANTISSA_BITS as i32)
            }
        } }
    }

    #[export_name="__fixunsdfti"]
    pub extern fn f64_as_u128(a: f64) -> u128_ {
        float_as_unsigned!(a, f64, u128_)
    }

    #[export_name="__fixunssfti"]
    pub extern fn f32_as_u128(a: f32) -> u128_ {
        float_as_unsigned!(a, f32, u128_)
    }

    macro_rules! float_as_signed {
        ($from: expr, $fromty: ty, $outty: ty) => {{
            use core::num::Float;
            let repr = $from.to_bytes();
            let sign = $from.signum();
            let exponent = $from.get_exponent();
            let mantissa = repr & <$fromty as FloatStuff>::MANTISSA_MASK;

            if exponent < 0 { return 0; }
            if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 {
                return if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() };
            }
            let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
                mantissa as $outty >> (<$fromty as FloatStuff>::MANTISSA_BITS as i32 - exponent)
            } else {
                mantissa as $outty << (exponent - <$fromty as FloatStuff>::MANTISSA_BITS as i32)
            };
            if sign >= 0.0 { r } else { -r }
        }}
    }

    #[export_name="__fixdfti"]
    pub extern fn f64_as_i128(a: f64) -> i128_ {
        float_as_signed!(a, f64, i128_)
    }

    #[export_name="__fixsfti"]
    pub extern fn f32_as_i128(a: f32) -> i128_ {
        float_as_signed!(a, f32, i128_)
    }

    #[export_name="__floattidf"]
    pub extern fn i128_as_f64(a: i128_) -> f64 {
        match a.signum() {
            1 => u128_as_f64(a.abs() as u128_),
            0 => 0.0,
            -1 => -u128_as_f64(a.abs() as u128_),
            _ => unimplemented()
        }
    }

    #[export_name="__floattisf"]
    pub extern fn i128_as_f32(a: i128_) -> f32 {
        match a.signum() {
            1 => u128_as_f32(a.abs() as u128_),
            0 => 0.0,
            -1 => -u128_as_f32(a.abs() as u128_),
            _ => unimplemented()
        }
    }

    #[export_name="__floatuntidf"]
    pub extern fn u128_as_f64(mut a: u128_) -> f64 {
        use ::core::f64::MANTISSA_DIGITS;
        if a == 0 { return 0.0; }
        let sd = 128 - a.leading_zeros();
        let mut e = sd - 1;
        const MD1 : u32 = MANTISSA_DIGITS + 1;
        const MD2 : u32 = MANTISSA_DIGITS + 2;

        if sd > MANTISSA_DIGITS {
            a = match sd {
                MD1 => a << 1,
                MD2 => a,
                _ => (a >> (sd - (MANTISSA_DIGITS + 2))) |
                     (if (a & (!0 >> (128 + MANTISSA_DIGITS + 2) - sd)) == 0 { 0 } else { 1 })
            };
            a |= if (a & 4) == 0 { 0 } else { 1 };
            a += 1;
            a >>= 2;
            if a & (1 << MANTISSA_DIGITS) != 0 {
                a >>= 1;
                e += 1;
            }
        } else {
            a <<= MANTISSA_DIGITS - sd;
        }
        unsafe {
            ::core::mem::transmute(((e as u64 + 1023) << 52) | (a as u64 & 0x000f_ffff_ffff_ffff))
        }
    }

    #[export_name="__floatuntisf"]
    pub extern fn u128_as_f32(mut a: u128_) -> f32 {
        use ::core::f32::MANTISSA_DIGITS;
        if a == 0 { return 0.0; }
        let sd = 128 - a.leading_zeros();
        let mut e = sd - 1;
        const MD1 : u32 = MANTISSA_DIGITS + 1;
        const MD2 : u32 = MANTISSA_DIGITS + 2;

        if sd > MANTISSA_DIGITS {
            a = match sd {
                MD1 => a << 1,
                MD2 => a,
                _ => (a >> (sd - (MANTISSA_DIGITS + 2))) |
                     (if (a & (!0 >> (128 + MANTISSA_DIGITS + 2) - sd)) == 0 { 0 } else { 1 })
            };
            a |= if (a & 4) == 0 { 0 } else { 1 };
            a += 1;
            a >>= 2;
            if a & (1 << MANTISSA_DIGITS) != 0 {
                a >>= 1;
                e += 1;
            }
        } else {
            a <<= MANTISSA_DIGITS - sd;
        }
        unsafe {
            ::core::mem::transmute(((e + 127) << 23) | (a as u32 & 0x007f_ffff))
        }
    }
}
<|endoftext|>


<commit_before>use hb;
use std;

use font::Font;
use common::{HarfbuzzObject, HbBox, Language, Tag};

pub type GlyphPosition = hb::hb_glyph_position_t;
pub type GlyphInfo = hb::hb_glyph_info_t;
pub type Feature = hb::hb_feature_t;

#[derive(Debug)]
pub(crate) struct GenericBuffer {
    _raw: hb::hb_buffer_t,
}
impl GenericBuffer {
    pub(crate) fn new() -> HbBox<GenericBuffer> {
        let buffer = unsafe { hb::hb_buffer_create() };
        unsafe { HbBox::from_raw(buffer) }
    }

    pub(crate) fn len(&self) -> usize {
        unsafe { hb::hb_buffer_get_length(self.as_raw()) as usize }
    }

    pub(crate) fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub(crate) fn add_str(&mut self, string: &str) {
        let utf8_ptr = string.as_ptr() as *const i8;
        unsafe {
            hb::hb_buffer_add_utf8(
                self.as_raw(),
                utf8_ptr,
                string.len() as i32,
                0,
                string.len() as i32,
            );
        }
    }

    pub(crate) fn set_direction(&mut self, direction: hb::hb_direction_t) {
        unsafe { hb::hb_buffer_set_direction(self.as_raw(), direction) };
    }

    /// Returns the `Buffer`'s text direction.
    pub(crate) fn get_direction(&self) -> hb::hb_direction_t {
        unsafe { hb::hb_buffer_get_direction(self.as_raw()) }
    }

    pub(crate) fn set_language(&mut self, lang: Language) {
        unsafe { hb::hb_buffer_set_language(self.as_raw(), lang.0) }
    }

    pub(crate) fn get_language(&self) -> Option<Language> {
        let raw_lang = unsafe { hb::hb_buffer_get_language(self.as_raw()) };
        if raw_lang.is_null() {
            None
        } else {
            Some(Language(raw_lang))
        }
    }

    pub(crate) fn set_script(&mut self, script: hb::hb_script_t) {
        unsafe { hb::hb_buffer_set_script(self.as_raw(), script) }
    }

    pub(crate) fn get_script(&self) -> hb::hb_script_t {
        unsafe { hb::hb_buffer_get_script(self.as_raw()) }
    }

    pub(crate) fn guess_segment_properties(&mut self) {
        unsafe { hb::hb_buffer_guess_segment_properties(self.as_raw()) };
    }

    pub(crate) fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        unsafe {
            let mut segment_props: hb::hb_segment_properties_t = std::mem::uninitialized();
            hb::hb_buffer_get_segment_properties(self.as_raw(), &mut segment_props as *mut _);
            segment_props
        }
    }

    pub(crate) fn shape(&mut self, font: &Font, features: &[Feature]) {
        unsafe {
            hb::hb_shape(
                font.as_raw(),
                self.as_raw(),
                features.as_ptr(),
                features.len() as u32,
            )
        };
    }

    pub(crate) fn clear_contents(&mut self) {
        unsafe { hb::hb_buffer_clear_contents(self.as_raw()) };
    }

    pub(crate) fn get_glyph_positions(&self) -> &[GlyphPosition] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_pos =
                hb::hb_buffer_get_glyph_positions(self.as_raw(), &mut length as *mut u32);
            std::slice::from_raw_parts(glyph_pos, length as usize)
        }
    }

    pub(crate) fn get_glyph_infos(&self) -> &[GlyphInfo] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_infos =
                hb::hb_buffer_get_glyph_infos(self.as_raw(), &mut length as *mut u32);
            std::slice::from_raw_parts(glyph_infos, length as usize)
        }
    }

    /// Reverse the `Buffer`'s contents.
    pub(crate) fn reverse(&mut self) {
        unsafe { hb::hb_buffer_reverse(self.as_raw()) };
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    pub(crate) fn reverse_range(&mut self, start: usize, end: usize) {
        assert!(start <= self.len(), end <= self.len());
        unsafe { hb::hb_buffer_reverse_range(self.as_raw(), start as u32, end as u32) }
    }

    pub(crate) fn content_type(&self) -> hb::hb_buffer_content_type_t {
        unsafe { hb::hb_buffer_get_content_type(self.as_raw()) }
    }
}

impl HarfbuzzObject for GenericBuffer {
    type Raw = hb::hb_buffer_t;

    unsafe fn reference(&self) {
        hb::hb_buffer_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_buffer_destroy(self.as_raw());
    }
}

/// This type provides an interface to create one of the buffer types from a raw harfbuzz pointer.
#[derive(Debug)]
pub enum TypedBuffer {
    Unicode(UnicodeBuffer),
    Glyphs(GlyphBuffer),
}

impl TypedBuffer {
    pub unsafe fn take_from_raw(raw: *mut hb::hb_buffer_t) -> Option<TypedBuffer> {
        let generic_buf: HbBox<GenericBuffer> = HbBox::from_raw(raw);
        let content_type = generic_buf.content_type();
        match content_type {
            hb::HB_BUFFER_CONTENT_TYPE_UNICODE => Some(TypedBuffer::Unicode(UnicodeBuffer(generic_buf))),
            hb::HB_BUFFER_CONTENT_TYPE_GLYPHS => Some(TypedBuffer::Glyphs(GlyphBuffer(generic_buf))),
            _ => None,
        }
    }
}

/// A `UnicodeBuffer` can be filled with unicode text and corresponding cluster indices.
///
/// The buffer manages an allocation for the unicode codepoints to be shaped. This allocation however
/// is reused for storing the results of the shaping operation in a `GlyphBuffer` object.
///
/// If you want to get a `UnicodeBuffer` from a pointer to a raw harfbuzz object, you need to use the
/// `from_raw` static method on `TypedBuffer`. This ensures that a buffer of correct type is created.
pub struct UnicodeBuffer(HbBox<GenericBuffer>);
impl UnicodeBuffer {
    /// Creates a new empty `Buffer`.
    ///
    /// # Examples
    /// ```
    /// use harfbuzz_rs::UnicodeBuffer;
    ///
    /// let buffer = UnicodeBuffer::new();
    /// assert!(buffer.is_empty());
    /// ```
    pub fn new() -> UnicodeBuffer {
        UnicodeBuffer(GenericBuffer::new())
    }

    /// Converts this buffer to a raw harfbuzz object pointer.
    pub fn into_raw(self) -> *mut hb::hb_buffer_t {
        HbBox::into_raw(self.0)
    }

    /// Returns the length of the data of the buffer.
    ///
    /// This corresponds to the number of unicode codepoints contained in the buffer.
    ///
    /// # Examples
    /// ```
    /// use harfbuzz_rs::UnicodeBuffer;
    ///
    /// let str1 = "Hello ";
    /// let buffer = UnicodeBuffer::new().add_str(str1);
    /// assert_eq!(buffer.len(), str1.len());
    ///
    /// let str2 = "😍🙈";
    /// let buffer = buffer.add_str(str2);
    /// assert_eq!(buffer.len(), str1.len() + 2);;
    /// ```
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Add the string slice `str_slice` to the `Buffer`'s array of codepoints.
    ///
    /// # Examples
    /// ```
    /// use harfbuzz_rs::UnicodeBuffer;
    ///
    /// let buffer = UnicodeBuffer::new().add_str("Hello");
    /// let buffer = buffer.add_str(" World");
    /// assert_eq!(buffer.string_lossy(), "Hello World");
    /// ```
    pub fn add_str(mut self, str_slice: &str) -> UnicodeBuffer {
        self.0.add_str(str_slice);
        self
    }

    /// Returns an Iterator over the stored unicode codepoints.
    ///
    /// # Examples
    /// ```
    /// use harfbuzz_rs::UnicodeBuffer;
    ///
    /// let buffer = UnicodeBuffer::new().add_str("ab");
    /// let mut iterator = buffer.codepoints();
    ///
    /// assert_eq!('a' as u32, iterator.next().unwrap());
    /// assert_eq!('b' as u32, iterator.next().unwrap());
    /// assert!(iterator.next().is_none());
    /// ```
    pub fn codepoints<'a>(&'a self) -> CodepointsIter<'a> {
        CodepointsIter {
            slice_iter: self.0.get_glyph_infos().iter(),
        }
    }

    /// Get the stored codepoints as a `String`.
    ///
    /// Invalid codepoints get replaced by the U+FFFD replacement character.
    pub fn string_lossy(&self) -> String {
        self.codepoints()
            .map(|cp| std::char::from_u32(cp).unwrap_or('\u{FFFD}'))
            .collect()
    }

    /// Set the text direction of the `Buffer`'s contents.
    pub fn set_direction(mut self, direction: hb::hb_direction_t) -> UnicodeBuffer {
        self.0.set_direction(direction);
        self
    }

    /// Returns the `Buffer`'s text direction.
    pub fn get_direction(&self) -> hb::hb_direction_t {
        self.0.get_direction()
    }

    /// Set the script from an ISO15924 tag.
    pub fn set_script(mut self, script: Tag) -> UnicodeBuffer {
        self.0
            .set_script(unsafe { hb::hb_script_from_iso15924_tag(script.0) });
        self
    }

    /// Get the ISO15924 script tag.
    pub fn get_script(&self) -> Tag {
        Tag(unsafe { hb::hb_script_to_iso15924_tag(self.0.get_script()) })
    }

    /// Set the buffer language.
    pub fn set_language(mut self, lang: Language) -> UnicodeBuffer {
        self.0.set_language(lang);
        self
    }

    /// Get the buffer language.
    pub fn get_language(&self) -> Option<Language> {
        self.0.get_language()
    }

    /// Guess the segment properties (direction, language, script) for the current buffer.
    pub fn guess_segment_properties(mut self) -> UnicodeBuffer {
        self.0.guess_segment_properties();
        self
    }

    /// Get the segment properties (direction, language, script) of the current buffer.
    pub fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        self.0.get_segment_properties()
    }

    /// Shape the contents of the buffer using the provided font and activating all OpenType features
    /// given in `features`.
    ///
    /// This function consumes the `UnicodeBuffer` and returns a `GlyphBuffer` containing the
    /// resulting glyph indices and the corresponding positioning information.
    pub fn shape(mut self, font: &Font, features: &[Feature]) -> GlyphBuffer {
        self = self.guess_segment_properties();
        self.0.shape(font, features);
        GlyphBuffer(self.0)
    }

    /// Clear the contents of the buffer (i.e. the stored string of unicode characters).
    ///
    /// # Examples
    /// ```
    /// use harfbuzz_rs::UnicodeBuffer;
    ///
    /// let buffer = UnicodeBuffer::new();
    /// let buffer = buffer.add_str("Test!");
    /// assert_eq!(buffer.len(), 5);
    /// let buffer = buffer.clear_contents();
    /// assert!(buffer.is_empty());
    /// ```
    pub fn clear_contents(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        self
    }
}

impl std::fmt::Debug for UnicodeBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("UnicodeBuffer")
            .field("content", &self.string_lossy())
            .field("direction", &self.get_direction())
            .field("language", &self.get_language())
            .field("script", &self.get_script())
            .finish()
    }
}

impl std::default::Default for UnicodeBuffer {
    fn default() -> UnicodeBuffer {
        UnicodeBuffer::new()
    }
}

/// An iterator over the codepoints stored in a `UnicodeBuffer`.
///
/// You get an iterator of this type from the `codepoints()` method on `UnicodeBuffer`.
#[derive(Debug)]
pub struct CodepointsIter<'a> {
    slice_iter: std::slice::Iter<'a, GlyphInfo>,
}

impl<'a> Iterator for CodepointsIter<'a> {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        self.slice_iter.next().map(|info| info.codepoint)
    }
}

/// A `GlyphBuffer` contains the resulting output information of the shaping process.
///
/// An object of this type is obtained through the `shape` function of a `UnicodeBuffer`.
pub struct GlyphBuffer(HbBox<GenericBuffer>);

impl GlyphBuffer {
    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Converts this buffer to a raw harfbuzz object pointer.
    pub fn into_raw(self) -> *mut hb::hb_buffer_t {
        HbBox::into_raw(self.0)
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Get the glyph positions.
    pub fn get_glyph_positions(&self) -> &[GlyphPosition] {
        self.0.get_glyph_positions()
    }

    /// Get the glyph infos.
    pub fn get_glyph_infos(&self) -> &[GlyphInfo] {
        self.0.get_glyph_infos()
    }

    /// Reverse the `Buffer`'s contents.
    pub fn reverse(&mut self) {
        self.0.reverse()
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    pub fn reverse_range(&mut self, start: usize, end: usize) {
        self.0.reverse_range(start, end)
    }

    /// Clears the contents of the glyph buffer and returns an empty `UnicodeBuffer` reusing the
    /// existing allocation.
    pub fn clear(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        UnicodeBuffer(self.0)
    }
}

impl std::fmt::Debug for GlyphBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("GlyphBuffer")
            .field("glyph_positions", &self.get_glyph_positions())
            .field("glyph_infos", &self.get_glyph_infos())
            .finish()
    }
}
<commit_msg>Improve documentation<commit_after>use hb;
use std;

use font::Font;
use common::{HarfbuzzObject, HbBox, Language, Tag};

pub type GlyphPosition = hb::hb_glyph_position_t;
pub type GlyphInfo = hb::hb_glyph_info_t;
pub type Feature = hb::hb_feature_t;

#[derive(Debug)]
pub(crate) struct GenericBuffer {
    _raw: hb::hb_buffer_t,
}
impl GenericBuffer {
    pub(crate) fn new() -> HbBox<GenericBuffer> {
        let buffer = unsafe { hb::hb_buffer_create() };
        unsafe { HbBox::from_raw(buffer) }
    }

    pub(crate) fn len(&self) -> usize {
        unsafe { hb::hb_buffer_get_length(self.as_raw()) as usize }
    }

    pub(crate) fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub(crate) fn add_str(&mut self, string: &str) {
        let utf8_ptr = string.as_ptr() as *const i8;
        unsafe {
            hb::hb_buffer_add_utf8(
                self.as_raw(),
                utf8_ptr,
                string.len() as i32,
                0,
                string.len() as i32,
            );
        }
    }

    pub(crate) fn set_direction(&mut self, direction: hb::hb_direction_t) {
        unsafe { hb::hb_buffer_set_direction(self.as_raw(), direction) };
    }

    /// Returns the `Buffer`'s text direction.
    pub(crate) fn get_direction(&self) -> hb::hb_direction_t {
        unsafe { hb::hb_buffer_get_direction(self.as_raw()) }
    }

    pub(crate) fn set_language(&mut self, lang: Language) {
        unsafe { hb::hb_buffer_set_language(self.as_raw(), lang.0) }
    }

    pub(crate) fn get_language(&self) -> Option<Language> {
        let raw_lang = unsafe { hb::hb_buffer_get_language(self.as_raw()) };
        if raw_lang.is_null() {
            None
        } else {
            Some(Language(raw_lang))
        }
    }

    pub(crate) fn set_script(&mut self, script: hb::hb_script_t) {
        unsafe { hb::hb_buffer_set_script(self.as_raw(), script) }
    }

    pub(crate) fn get_script(&self) -> hb::hb_script_t {
        unsafe { hb::hb_buffer_get_script(self.as_raw()) }
    }

    pub(crate) fn guess_segment_properties(&mut self) {
        unsafe { hb::hb_buffer_guess_segment_properties(self.as_raw()) };
    }

    pub(crate) fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        unsafe {
            let mut segment_props: hb::hb_segment_properties_t = std::mem::uninitialized();
            hb::hb_buffer_get_segment_properties(self.as_raw(), &mut segment_props as *mut _);
            segment_props
        }
    }

    pub(crate) fn shape(&mut self, font: &Font, features: &[Feature]) {
        unsafe {
            hb::hb_shape(
                font.as_raw(),
                self.as_raw(),
                features.as_ptr(),
                features.len() as u32,
            )
        };
    }

    pub(crate) fn clear_contents(&mut self) {
        unsafe { hb::hb_buffer_clear_contents(self.as_raw()) };
    }

    pub(crate) fn get_glyph_positions(&self) -> &[GlyphPosition] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_pos =
                hb::hb_buffer_get_glyph_positions(self.as_raw(), &mut length as *mut u32);
            std::slice::from_raw_parts(glyph_pos, length as usize)
        }
    }

    pub(crate) fn get_glyph_infos(&self) -> &[GlyphInfo] {
        unsafe {
            let mut length: u32 = 0;
            let glyph_infos = hb::hb_buffer_get_glyph_infos(self.as_raw(), &mut length as *mut u32);
            std::slice::from_raw_parts(glyph_infos, length as usize)
        }
    }

    /// Reverse the `Buffer`'s contents.
    pub(crate) fn reverse(&mut self) {
        unsafe { hb::hb_buffer_reverse(self.as_raw()) };
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    pub(crate) fn reverse_range(&mut self, start: usize, end: usize) {
        assert!(start <= self.len(), end <= self.len());
        unsafe { hb::hb_buffer_reverse_range(self.as_raw(), start as u32, end as u32) }
    }

    pub(crate) fn content_type(&self) -> hb::hb_buffer_content_type_t {
        unsafe { hb::hb_buffer_get_content_type(self.as_raw()) }
    }
}

impl HarfbuzzObject for GenericBuffer {
    type Raw = hb::hb_buffer_t;

    unsafe fn reference(&self) {
        hb::hb_buffer_reference(self.as_raw());
    }

    unsafe fn dereference(&self) {
        hb::hb_buffer_destroy(self.as_raw());
    }
}

/// This type provides an interface to create one of the buffer types from a raw harfbuzz pointer.
#[derive(Debug)]
pub enum TypedBuffer {
    Unicode(UnicodeBuffer),
    Glyphs(GlyphBuffer),
}

impl TypedBuffer {
    pub unsafe fn take_from_raw(raw: *mut hb::hb_buffer_t) -> Option<TypedBuffer> {
        let generic_buf: HbBox<GenericBuffer> = HbBox::from_raw(raw);
        let content_type = generic_buf.content_type();
        match content_type {
            hb::HB_BUFFER_CONTENT_TYPE_UNICODE => {
                Some(TypedBuffer::Unicode(UnicodeBuffer(generic_buf)))
            }
            hb::HB_BUFFER_CONTENT_TYPE_GLYPHS => {
                Some(TypedBuffer::Glyphs(GlyphBuffer(generic_buf)))
            }
            _ => None,
        }
    }
}

/// A `UnicodeBuffer` can be filled with unicode text and corresponding cluster indices.
///
/// The buffer manages an allocation for the unicode codepoints to be shaped. This allocation however
/// is reused for storing the results of the shaping operation in a `GlyphBuffer` object. The intended
/// usage is to keep one (or e.g. one per thread) `UnicodeBuffer` around. When needed, you fill it with
/// text that should be shaped and call `.shape()` on it. That method returns a `GlyphBuffer` object
/// containing the shaped glyph indices. Once you got the needed information out of the `GlyphBuffer`
/// you call its `.clear()` method which in turn gives you a fresh `UnicodeBuffer` (actually using the
/// original allocation). This buffer can then be used to shape more text.
///
/// If you want to get a `UnicodeBuffer` from a pointer to a raw harfbuzz object, you need to use the
/// `from_raw` static method on `TypedBuffer`. This ensures that a buffer of correct type is created.
pub struct UnicodeBuffer(HbBox<GenericBuffer>);
impl UnicodeBuffer {
    /// Creates a new empty `Buffer`.
    ///
    /// # Examples
    /// ```
    /// use harfbuzz_rs::UnicodeBuffer;
    ///
    /// let buffer = UnicodeBuffer::new();
    /// assert!(buffer.is_empty());
    /// ```
    pub fn new() -> UnicodeBuffer {
        UnicodeBuffer(GenericBuffer::new())
    }

    /// Converts this buffer to a raw harfbuzz object pointer.
    pub fn into_raw(self) -> *mut hb::hb_buffer_t {
        HbBox::into_raw(self.0)
    }

    /// Returns the length of the data of the buffer.
    ///
    /// This corresponds to the number of unicode codepoints contained in the buffer.
    ///
    /// # Examples
    /// ```
    /// use harfbuzz_rs::UnicodeBuffer;
    ///
    /// let str1 = "Hello ";
    /// let buffer = UnicodeBuffer::new().add_str(str1);
    /// assert_eq!(buffer.len(), str1.len());
    ///
    /// let str2 = "😍🙈";
    /// let buffer = buffer.add_str(str2);
    /// assert_eq!(buffer.len(), str1.len() + 2);;
    /// ```
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Add the string slice `str_slice` to the `Buffer`'s array of codepoints.
    ///
    /// # Examples
    /// ```
    /// use harfbuzz_rs::UnicodeBuffer;
    ///
    /// let buffer = UnicodeBuffer::new().add_str("Hello");
    /// let buffer = buffer.add_str(" World");
    /// assert_eq!(buffer.string_lossy(), "Hello World");
    /// ```
    pub fn add_str(mut self, str_slice: &str) -> UnicodeBuffer {
        self.0.add_str(str_slice);
        self
    }

    /// Returns an Iterator over the stored unicode codepoints.
    ///
    /// # Examples
    /// ```
    /// use harfbuzz_rs::UnicodeBuffer;
    ///
    /// let buffer = UnicodeBuffer::new().add_str("ab");
    /// let mut iterator = buffer.codepoints();
    ///
    /// assert_eq!('a' as u32, iterator.next().unwrap());
    /// assert_eq!('b' as u32, iterator.next().unwrap());
    /// assert!(iterator.next().is_none());
    /// ```
    pub fn codepoints<'a>(&'a self) -> Codepoints<'a> {
        Codepoints {
            slice_iter: self.0.get_glyph_infos().iter(),
        }
    }

    /// Get the stored codepoints as a `String`.
    ///
    /// Invalid codepoints get replaced by the U+FFFD replacement character.
    pub fn string_lossy(&self) -> String {
        self.codepoints()
            .map(|cp| std::char::from_u32(cp).unwrap_or('\u{FFFD}'))
            .collect()
    }

    /// Set the text direction of the `Buffer`'s contents.
    pub fn set_direction(mut self, direction: hb::hb_direction_t) -> UnicodeBuffer {
        self.0.set_direction(direction);
        self
    }

    /// Returns the `Buffer`'s text direction.
    pub fn get_direction(&self) -> hb::hb_direction_t {
        self.0.get_direction()
    }

    /// Set the script from an ISO15924 tag.
    pub fn set_script(mut self, script: Tag) -> UnicodeBuffer {
        self.0
            .set_script(unsafe { hb::hb_script_from_iso15924_tag(script.0) });
        self
    }

    /// Get the ISO15924 script tag.
    pub fn get_script(&self) -> Tag {
        Tag(unsafe { hb::hb_script_to_iso15924_tag(self.0.get_script()) })
    }

    /// Set the buffer language.
    pub fn set_language(mut self, lang: Language) -> UnicodeBuffer {
        self.0.set_language(lang);
        self
    }

    /// Get the buffer language.
    pub fn get_language(&self) -> Option<Language> {
        self.0.get_language()
    }

    /// Guess the segment properties (direction, language, script) for the current buffer.
    pub fn guess_segment_properties(mut self) -> UnicodeBuffer {
        self.0.guess_segment_properties();
        self
    }

    /// Get the segment properties (direction, language, script) of the current buffer.
    pub fn get_segment_properties(&self) -> hb::hb_segment_properties_t {
        self.0.get_segment_properties()
    }

    /// Shape the contents of the buffer using the provided font and activating all OpenType features
    /// given in `features`.
    ///
    /// This function consumes the `UnicodeBuffer` and returns a `GlyphBuffer` containing the
    /// resulting glyph indices and the corresponding positioning information.
    pub fn shape(mut self, font: &Font, features: &[Feature]) -> GlyphBuffer {
        self = self.guess_segment_properties();
        self.0.shape(font, features);
        GlyphBuffer(self.0)
    }

    /// Clear the contents of the buffer (i.e. the stored string of unicode characters).
    ///
    /// # Examples
    /// ```
    /// use harfbuzz_rs::UnicodeBuffer;
    ///
    /// let buffer = UnicodeBuffer::new();
    /// let buffer = buffer.add_str("Test!");
    /// assert_eq!(buffer.len(), 5);
    /// let buffer = buffer.clear_contents();
    /// assert!(buffer.is_empty());
    /// ```
    pub fn clear_contents(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        self
    }
}

impl std::fmt::Debug for UnicodeBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("UnicodeBuffer")
            .field("content", &self.string_lossy())
            .field("direction", &self.get_direction())
            .field("language", &self.get_language())
            .field("script", &self.get_script())
            .finish()
    }
}

impl std::default::Default for UnicodeBuffer {
    fn default() -> UnicodeBuffer {
        UnicodeBuffer::new()
    }
}

/// An iterator over the codepoints stored in a `UnicodeBuffer`.
///
/// You get an iterator of this type from the `.codepoints()` method on `UnicodeBuffer`.
/// I yields `u32`s that should be interpreted as unicode codepoints stored
/// in the underlying buffer.
#[derive(Debug, Clone)]
pub struct Codepoints<'a> {
    slice_iter: std::slice::Iter<'a, GlyphInfo>,
}

impl<'a> Iterator for Codepoints<'a> {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        self.slice_iter.next().map(|info| info.codepoint)
    }
}

/// A `GlyphBuffer` contains the resulting output information of the shaping process.
///
/// An object of this type is obtained through the `shape` function of a `UnicodeBuffer`.
pub struct GlyphBuffer(HbBox<GenericBuffer>);

impl GlyphBuffer {
    /// Returns the length of the data of the buffer.
    ///
    /// When called before shaping this is the number of unicode codepoints contained in the
    /// buffer. When called after shaping it returns the number of glyphs stored.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Converts this buffer to a raw harfbuzz object pointer.
    pub fn into_raw(self) -> *mut hb::hb_buffer_t {
        HbBox::into_raw(self.0)
    }

    /// Returns `true` if the buffer contains no elements.
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    /// Get the glyph positions.
    pub fn get_glyph_positions(&self) -> &[GlyphPosition] {
        self.0.get_glyph_positions()
    }

    /// Get the glyph infos.
    pub fn get_glyph_infos(&self) -> &[GlyphInfo] {
        self.0.get_glyph_infos()
    }

    /// Reverse the `Buffer`'s contents.
    pub fn reverse(&mut self) {
        self.0.reverse()
    }

    /// Reverse the `Buffer`'s contents in the range from `start` to `end`.
    pub fn reverse_range(&mut self, start: usize, end: usize) {
        self.0.reverse_range(start, end)
    }

    /// Clears the contents of the glyph buffer and returns an empty `UnicodeBuffer` reusing the
    /// existing allocation.
    pub fn clear(mut self) -> UnicodeBuffer {
        self.0.clear_contents();
        UnicodeBuffer(self.0)
    }
}

impl std::fmt::Debug for GlyphBuffer {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        fmt.debug_struct("GlyphBuffer")
            .field("glyph_positions", &self.get_glyph_positions())
            .field("glyph_infos", &self.get_glyph_infos())
            .finish()
    }
}
<|endoftext|>


<commit_before>use cranelift_codegen::ir;
use cranelift_faerie::traps::FaerieTrapManifest;

use byteorder::{LittleEndian, WriteBytesExt};
use faerie::{Artifact, Decl, Link};
use failure::{Error, ResultExt};
use std::io::Cursor;

pub fn write_trap_manifest(manifest: &FaerieTrapManifest, obj: &mut Artifact) -> Result<(), Error> {
    // declare traptable symbol
    let manifest_len_sym = "lucet_trap_manifest_len";
    obj.declare(
        &manifest_len_sym,
        Decl::data().global(),
    )
    .context(format!("declaring {}", &manifest_len_sym))?;

    let manifest_sym = "lucet_trap_manifest";
    obj.declare(
        &manifest_sym,
        Decl::data().global(),
    )
    .context(format!("declaring {}", &manifest_sym))?;

    let manifest_len = manifest.sinks.len();
    let mut manifest_len_buf: Vec<u8> = Vec::new();
    manifest_len_buf
        .write_u32::<LittleEndian>(manifest_len as u32)
        .unwrap();
    obj.define(&manifest_len_sym, manifest_len_buf)
        .context(format!("defining {}", &manifest_len_sym))?;

    // Manifests are serialized with the following struct elements in order:
    // { func_start: ptr, func_len: u64, traps: ptr, traps_len: u64 }
    let manifest_row_size = 8 * 4;
    let mut manifest_buf: Cursor<Vec<u8>> =
        Cursor::new(Vec::with_capacity(manifest_len * manifest_row_size));

    for sink in manifest.sinks.iter() {
        let func_sym = &sink.name;
        let trap_sym = trap_sym_for_func(func_sym);

        // declare function-level trap table
        obj.declare(
            &trap_sym,
            Decl::data().global(),
        )
        .context(format!("declaring {}", &trap_sym))?;

        // function symbol is provided via a link (abs8 relocation)
        obj.link(Link {
            from: &manifest_sym,
            to: func_sym,
            at: manifest_buf.position(),
        })
        .context("linking function sym into trap manifest")?;
        manifest_buf.write_u64::<LittleEndian>(0).unwrap();

        // write function length
        manifest_buf
            .write_u64::<LittleEndian>(sink.code_size as u64)
            .unwrap();

        // table for this function is provided via a link (abs8 relocation)
        obj.link(Link {
            from: &manifest_sym,
            to: &trap_sym,
            at: manifest_buf.position(),
        })
        .context("linking trap table into trap manifest")?;
        manifest_buf.write_u64::<LittleEndian>(0).unwrap();

        // finally, write the length of the trap table
        manifest_buf
            .write_u64::<LittleEndian>(sink.sites.len() as u64)
            .unwrap();

        // ok, now write the actual function-level trap table
        let mut traps: Vec<u8> = Vec::new();

        for site in sink.sites.iter() {
            // write offset into trap table
            traps.write_u32::<LittleEndian>(site.offset as u32).unwrap();
            // write serialized trap code into trap table
            traps
                .write_u32::<LittleEndian>(serialize_trapcode(site.code))
                .unwrap();
        }

        // and finally write the function trap table into the object
        obj.define(&trap_sym, traps)
            .context(format!("defining {}", &trap_sym))?;
    }

    obj.define(&manifest_sym, manifest_buf.into_inner())
        .context(format!("defining {}", &manifest_sym))?;

    // iterate over tables:
    //   write empty relocation thunk
    //   link from traptable symbol + thunk offset to function symbol
    //   write trapsite count
    //
    //   iterate over trapsites:
    //     write offset
    //     write trapcode

    Ok(())
}

fn trap_sym_for_func(sym: &str) -> String {
    return format!("lucet_trap_table_{}", sym);
}

// Trapcodes can be thought of as a tuple of (type, subtype). Each are
// represented as a 16-bit unsigned integer. These are packed into a u32
// wherein the type occupies the low 16 bites and the subtype takes the
// high bits.
//
// Not all types have subtypes. Currently, only the user User type has a
// subtype.
fn serialize_trapcode(code: ir::TrapCode) -> u32 {
    match code {
        ir::TrapCode::StackOverflow => 0,
        ir::TrapCode::HeapOutOfBounds => 1,
        ir::TrapCode::OutOfBounds => 2,
        ir::TrapCode::IndirectCallToNull => 3,
        ir::TrapCode::BadSignature => 4,
        ir::TrapCode::IntegerOverflow => 5,
        ir::TrapCode::IntegerDivisionByZero => 6,
        ir::TrapCode::BadConversionToInteger => 7,
        ir::TrapCode::Interrupt => 8,
        ir::TrapCode::TableOutOfBounds => 9,
        ir::TrapCode::UnreachableCodeReached => (u16::max_value() - 1) as u32, // XXX this used to be User(0)
        ir::TrapCode::User(x) => ((u16::max_value() - 1) as u32) | ((x as u32) << 16),
    }
}
<commit_msg>indent<commit_after>use cranelift_codegen::ir;
use cranelift_faerie::traps::FaerieTrapManifest;

use byteorder::{LittleEndian, WriteBytesExt};
use faerie::{Artifact, Decl, Link};
use failure::{Error, ResultExt};
use std::io::Cursor;

pub fn write_trap_manifest(manifest: &FaerieTrapManifest, obj: &mut Artifact) -> Result<(), Error> {
    // declare traptable symbol
    let manifest_len_sym = "lucet_trap_manifest_len";
    obj.declare(&manifest_len_sym, Decl::data().global())
        .context(format!("declaring {}", &manifest_len_sym))?;

    let manifest_sym = "lucet_trap_manifest";
    obj.declare(&manifest_sym, Decl::data().global())
        .context(format!("declaring {}", &manifest_sym))?;

    let manifest_len = manifest.sinks.len();
    let mut manifest_len_buf: Vec<u8> = Vec::new();
    manifest_len_buf
        .write_u32::<LittleEndian>(manifest_len as u32)
        .unwrap();
    obj.define(&manifest_len_sym, manifest_len_buf)
        .context(format!("defining {}", &manifest_len_sym))?;

    // Manifests are serialized with the following struct elements in order:
    // { func_start: ptr, func_len: u64, traps: ptr, traps_len: u64 }
    let manifest_row_size = 8 * 4;
    let mut manifest_buf: Cursor<Vec<u8>> =
        Cursor::new(Vec::with_capacity(manifest_len * manifest_row_size));

    for sink in manifest.sinks.iter() {
        let func_sym = &sink.name;
        let trap_sym = trap_sym_for_func(func_sym);

        // declare function-level trap table
        obj.declare(&trap_sym, Decl::data().global())
            .context(format!("declaring {}", &trap_sym))?;

        // function symbol is provided via a link (abs8 relocation)
        obj.link(Link {
            from: &manifest_sym,
            to: func_sym,
            at: manifest_buf.position(),
        })
        .context("linking function sym into trap manifest")?;
        manifest_buf.write_u64::<LittleEndian>(0).unwrap();

        // write function length
        manifest_buf
            .write_u64::<LittleEndian>(sink.code_size as u64)
            .unwrap();

        // table for this function is provided via a link (abs8 relocation)
        obj.link(Link {
            from: &manifest_sym,
            to: &trap_sym,
            at: manifest_buf.position(),
        })
        .context("linking trap table into trap manifest")?;
        manifest_buf.write_u64::<LittleEndian>(0).unwrap();

        // finally, write the length of the trap table
        manifest_buf
            .write_u64::<LittleEndian>(sink.sites.len() as u64)
            .unwrap();

        // ok, now write the actual function-level trap table
        let mut traps: Vec<u8> = Vec::new();

        for site in sink.sites.iter() {
            // write offset into trap table
            traps.write_u32::<LittleEndian>(site.offset as u32).unwrap();
            // write serialized trap code into trap table
            traps
                .write_u32::<LittleEndian>(serialize_trapcode(site.code))
                .unwrap();
        }

        // and finally write the function trap table into the object
        obj.define(&trap_sym, traps)
            .context(format!("defining {}", &trap_sym))?;
    }

    obj.define(&manifest_sym, manifest_buf.into_inner())
        .context(format!("defining {}", &manifest_sym))?;

    // iterate over tables:
    //   write empty relocation thunk
    //   link from traptable symbol + thunk offset to function symbol
    //   write trapsite count
    //
    //   iterate over trapsites:
    //     write offset
    //     write trapcode

    Ok(())
}

fn trap_sym_for_func(sym: &str) -> String {
    return format!("lucet_trap_table_{}", sym);
}

// Trapcodes can be thought of as a tuple of (type, subtype). Each are
// represented as a 16-bit unsigned integer. These are packed into a u32
// wherein the type occupies the low 16 bites and the subtype takes the
// high bits.
//
// Not all types have subtypes. Currently, only the user User type has a
// subtype.
fn serialize_trapcode(code: ir::TrapCode) -> u32 {
    match code {
        ir::TrapCode::StackOverflow => 0,
        ir::TrapCode::HeapOutOfBounds => 1,
        ir::TrapCode::OutOfBounds => 2,
        ir::TrapCode::IndirectCallToNull => 3,
        ir::TrapCode::BadSignature => 4,
        ir::TrapCode::IntegerOverflow => 5,
        ir::TrapCode::IntegerDivisionByZero => 6,
        ir::TrapCode::BadConversionToInteger => 7,
        ir::TrapCode::Interrupt => 8,
        ir::TrapCode::TableOutOfBounds => 9,
        ir::TrapCode::UnreachableCodeReached => (u16::max_value() - 1) as u32, // XXX this used to be User(0)
        ir::TrapCode::User(x) => ((u16::max_value() - 1) as u32) | ((x as u32) << 16),
    }
}
<|endoftext|>