<commit_before>use rustc_middle::mir;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::{self, Ty};
use std::borrow::{Borrow, Cow};
use std::collections::hash_map::Entry;
use std::hash::Hash;

use rustc_data_structures::fx::FxHashMap;

use rustc_ast::ast::Mutability;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::AssertMessage;
use rustc_span::symbol::Symbol;

use crate::interpret::{
    self, AllocId, Allocation, GlobalId, ImmTy, InterpCx, InterpResult, Memory, MemoryKind, OpTy,
    PlaceTy, Pointer, Scalar,
};

use super::error::*;

impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter> {
    /// Evaluate a const function where all arguments (if any) are zero-sized types.
    /// The evaluation is memoized thanks to the query system.
    ///
    /// Returns `true` if the call has been evaluated.
    fn try_eval_const_fn_call(
        &mut self,
        instance: ty::Instance<'tcx>,
        ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
        args: &[OpTy<'tcx>],
    ) -> InterpResult<'tcx, bool> {
        trace!("try_eval_const_fn_call: {:?}", instance);
        // Because `#[track_caller]` adds an implicit non-ZST argument, we also cannot
        // perform this optimization on items tagged with it.
        if instance.def.requires_caller_location(self.tcx()) {
            return Ok(false);
        }
        // For the moment we only do this for functions which take no arguments
        // (or all arguments are ZSTs) so that we don't memoize too much.
        if args.iter().any(|a| !a.layout.is_zst()) {
            return Ok(false);
        }

        let dest = match ret {
            Some((dest, _)) => dest,
            // Don't memoize diverging function calls.
            None => return Ok(false),
        };

        let gid = GlobalId { instance, promoted: None };

        let place = self.const_eval_raw(gid)?;

        self.copy_op(place.into(), dest)?;

        self.return_to_block(ret.map(|r| r.1))?;
        self.dump_place(*dest);
        Ok(true)
    }

    /// "Intercept" a function call to a panic-related function
    /// because we have something special to do for it.
    /// If this returns successfully (`Ok`), the function should just be evaluated normally.
    fn hook_panic_fn(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx>],
    ) -> InterpResult<'tcx> {
        let def_id = instance.def_id();
        if Some(def_id) == self.tcx.lang_items().panic_fn()
            || Some(def_id) == self.tcx.lang_items().begin_panic_fn()
        {
            // &'static str
            assert!(args.len() == 1);

            let msg_place = self.deref_operand(args[0])?;
            let msg = Symbol::intern(self.read_str(msg_place)?);
            let span = self.find_closest_untracked_caller_location();
            let (file, line, col) = self.location_triple_for_span(span);
            Err(ConstEvalErrKind::Panic { msg, file, line, col }.into())
        } else {
            Ok(())
        }
    }
}

/// Extra machine state for CTFE, and the Machine instance
pub struct CompileTimeInterpreter {
    /// For now, the number of terminators that can be evaluated before we throw a resource
    /// exhuastion error.
    ///
    /// Setting this to `0` disables the limit and allows the interpreter to run forever.
    pub steps_remaining: usize,
}

#[derive(Copy, Clone, Debug)]
pub struct MemoryExtra {
    /// Whether this machine may read from statics
    pub(super) can_access_statics: bool,
}

impl CompileTimeInterpreter {
    pub(super) fn new(const_eval_limit: usize) -> Self {
        CompileTimeInterpreter { steps_remaining: const_eval_limit }
    }
}

impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
    #[inline(always)]
    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
    where
        K: Borrow<Q>,
    {
        FxHashMap::contains_key(self, k)
    }

    #[inline(always)]
    fn insert(&mut self, k: K, v: V) -> Option<V> {
        FxHashMap::insert(self, k, v)
    }

    #[inline(always)]
    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
    where
        K: Borrow<Q>,
    {
        FxHashMap::remove(self, k)
    }

    #[inline(always)]
    fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
        self.iter().filter_map(move |(k, v)| f(k, &*v)).collect()
    }

    #[inline(always)]
    fn get_or<E>(&self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Result<&V, E> {
        match self.get(&k) {
            Some(v) => Ok(v),
            None => {
                vacant()?;
                bug!("The CTFE machine shouldn't ever need to extend the alloc_map when reading")
            }
        }
    }

    #[inline(always)]
    fn get_mut_or<E>(&mut self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Result<&mut V, E> {
        match self.entry(k) {
            Entry::Occupied(e) => Ok(e.into_mut()),
            Entry::Vacant(e) => {
                let v = vacant()?;
                Ok(e.insert(v))
            }
        }
    }
}

crate type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter>;

impl interpret::MayLeak for ! {
    #[inline(always)]
    fn may_leak(self) -> bool {
        // `self` is uninhabited
        self
    }
}

impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter {
    type MemoryKind = !;
    type PointerTag = ();
    type ExtraFnVal = !;

    type FrameExtra = ();
    type MemoryExtra = MemoryExtra;
    type AllocExtra = ();

    type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>;

    const GLOBAL_KIND: Option<!> = None; // no copying of globals from `tcx` to machine memory

    #[inline(always)]
    fn enforce_alignment(_memory_extra: &Self::MemoryExtra) -> bool {
        // We do not check for alignment to avoid having to carry an `Align`
        // in `ConstValue::ByRef`.
        false
    }

    #[inline(always)]
    fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
        false // for now, we don't enforce validity
    }

    fn find_mir_or_eval_fn(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx>],
        ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
        _unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts
    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
        debug!("find_mir_or_eval_fn: {:?}", instance);

        // Only check non-glue functions
        if let ty::InstanceDef::Item(def_id) = instance.def {
            // Execution might have wandered off into other crates, so we cannot do a stability-
            // sensitive check here.  But we can at least rule out functions that are not const
            // at all.
            if ecx.tcx.is_const_fn_raw(def_id) {
                // If this function is a `const fn` then under certain circumstances we
                // can evaluate call via the query system, thus memoizing all future calls.
                if ecx.try_eval_const_fn_call(instance, ret, args)? {
                    return Ok(None);
                }
            } else {
                // Some functions we support even if they are non-const -- but avoid testing
                // that for const fn!
                ecx.hook_panic_fn(instance, args)?;
                // We certainly do *not* want to actually call the fn
                // though, so be sure we return here.
                throw_unsup_format!("calling non-const function `{}`", instance)
            }
        }
        // This is a const fn. Call it.
        Ok(Some(match ecx.load_mir(instance.def, None) {
            Ok(body) => *body,
            Err(err) => {
                if let err_unsup!(NoMirFor(did)) = err.kind {
                    let path = ecx.tcx.def_path_str(did);
                    return Err(ConstEvalErrKind::NeedsRfc(format!(
                        "calling extern function `{}`",
                        path
                    ))
                    .into());
                }
                return Err(err);
            }
        }))
    }

    fn call_extra_fn(
        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
        fn_val: !,
        _args: &[OpTy<'tcx>],
        _ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
        _unwind: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx> {
        match fn_val {}
    }

    fn call_intrinsic(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx>],
        ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
        _unwind: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx> {
        if ecx.emulate_intrinsic(instance, args, ret)? {
            return Ok(());
        }
        // An intrinsic that we do not support
        let intrinsic_name = ecx.tcx.item_name(instance.def_id());
        Err(ConstEvalErrKind::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into())
    }

    fn assert_panic(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        msg: &AssertMessage<'tcx>,
        _unwind: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx> {
        use rustc_middle::mir::AssertKind::*;
        // Convert `AssertKind<Operand>` to `AssertKind<u64>`.
        let err = match msg {
            BoundsCheck { ref len, ref index } => {
                let len = ecx
                    .read_immediate(ecx.eval_operand(len, None)?)
                    .expect("can't eval len")
                    .to_scalar()?
                    .to_machine_usize(&*ecx)?;
                let index = ecx
                    .read_immediate(ecx.eval_operand(index, None)?)
                    .expect("can't eval index")
                    .to_scalar()?
                    .to_machine_usize(&*ecx)?;
                BoundsCheck { len, index }
            }
            Overflow(op) => Overflow(*op),
            OverflowNeg => OverflowNeg,
            DivisionByZero => DivisionByZero,
            RemainderByZero => RemainderByZero,
            ResumedAfterReturn(generator_kind) => ResumedAfterReturn(*generator_kind),
            ResumedAfterPanic(generator_kind) => ResumedAfterPanic(*generator_kind),
        };
        Err(ConstEvalErrKind::AssertFailure(err).into())
    }

    fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> {
        Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into())
    }

    fn binary_ptr_op(
        _ecx: &InterpCx<'mir, 'tcx, Self>,
        _bin_op: mir::BinOp,
        _left: ImmTy<'tcx>,
        _right: ImmTy<'tcx>,
    ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
        Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
    }

    #[inline(always)]
    fn init_allocation_extra<'b>(
        _memory_extra: &MemoryExtra,
        _id: AllocId,
        alloc: Cow<'b, Allocation>,
        _kind: Option<MemoryKind<!>>,
    ) -> (Cow<'b, Allocation<Self::PointerTag>>, Self::PointerTag) {
        // We do not use a tag so we can just cheaply forward the allocation
        (alloc, ())
    }

    #[inline(always)]
    fn tag_global_base_pointer(_memory_extra: &MemoryExtra, _id: AllocId) -> Self::PointerTag {}

    fn box_alloc(
        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
        _dest: PlaceTy<'tcx>,
    ) -> InterpResult<'tcx> {
        Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into())
    }

    fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
        // The step limit has already been hit in a previous call to `before_terminator`.
        if ecx.machine.steps_remaining == 0 {
            return Ok(());
        }

        ecx.machine.steps_remaining -= 1;
        if ecx.machine.steps_remaining == 0 {
            throw_exhaust!(StepLimitReached)
        }

        Ok(())
    }

    #[inline(always)]
    fn stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
        Ok(())
    }

    fn before_access_global(
        memory_extra: &MemoryExtra,
        alloc_id: AllocId,
        allocation: &Allocation,
        static_def_id: Option<DefId>,
        is_write: bool,
    ) -> InterpResult<'tcx> {
        if is_write && allocation.mutability == Mutability::Not {
            Err(err_ub!(WriteToReadOnly(alloc_id)).into())
        } else if is_write {
            Err(ConstEvalErrKind::ModifiedGlobal.into())
        } else if memory_extra.can_access_statics || static_def_id.is_none() {
            // `static_def_id.is_none()` indicates this is not a static, but a const or so.
            Ok(())
        } else {
            Err(ConstEvalErrKind::ConstAccessesStatic.into())
        }
    }
}

// Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups
// so we can end up having a file with just that impl, but for now, let's keep the impl discoverable
// at the bottom of this file.
<commit_msg>Rollup merge of #70947 - RalfJung:ctfe-no-read-mut-global, r=oli-obk<commit_after>use rustc_middle::mir;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::{self, Ty};
use std::borrow::{Borrow, Cow};
use std::collections::hash_map::Entry;
use std::hash::Hash;

use rustc_data_structures::fx::FxHashMap;

use rustc_ast::ast::Mutability;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::AssertMessage;
use rustc_span::symbol::Symbol;

use crate::interpret::{
    self, AllocId, Allocation, GlobalId, ImmTy, InterpCx, InterpResult, Memory, MemoryKind, OpTy,
    PlaceTy, Pointer, Scalar,
};

use super::error::*;

impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter> {
    /// Evaluate a const function where all arguments (if any) are zero-sized types.
    /// The evaluation is memoized thanks to the query system.
    ///
    /// Returns `true` if the call has been evaluated.
    fn try_eval_const_fn_call(
        &mut self,
        instance: ty::Instance<'tcx>,
        ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
        args: &[OpTy<'tcx>],
    ) -> InterpResult<'tcx, bool> {
        trace!("try_eval_const_fn_call: {:?}", instance);
        // Because `#[track_caller]` adds an implicit non-ZST argument, we also cannot
        // perform this optimization on items tagged with it.
        if instance.def.requires_caller_location(self.tcx()) {
            return Ok(false);
        }
        // For the moment we only do this for functions which take no arguments
        // (or all arguments are ZSTs) so that we don't memoize too much.
        if args.iter().any(|a| !a.layout.is_zst()) {
            return Ok(false);
        }

        let dest = match ret {
            Some((dest, _)) => dest,
            // Don't memoize diverging function calls.
            None => return Ok(false),
        };

        let gid = GlobalId { instance, promoted: None };

        let place = self.const_eval_raw(gid)?;

        self.copy_op(place.into(), dest)?;

        self.return_to_block(ret.map(|r| r.1))?;
        self.dump_place(*dest);
        Ok(true)
    }

    /// "Intercept" a function call to a panic-related function
    /// because we have something special to do for it.
    /// If this returns successfully (`Ok`), the function should just be evaluated normally.
    fn hook_panic_fn(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx>],
    ) -> InterpResult<'tcx> {
        let def_id = instance.def_id();
        if Some(def_id) == self.tcx.lang_items().panic_fn()
            || Some(def_id) == self.tcx.lang_items().begin_panic_fn()
        {
            // &'static str
            assert!(args.len() == 1);

            let msg_place = self.deref_operand(args[0])?;
            let msg = Symbol::intern(self.read_str(msg_place)?);
            let span = self.find_closest_untracked_caller_location();
            let (file, line, col) = self.location_triple_for_span(span);
            Err(ConstEvalErrKind::Panic { msg, file, line, col }.into())
        } else {
            Ok(())
        }
    }
}

/// Extra machine state for CTFE, and the Machine instance
pub struct CompileTimeInterpreter {
    /// For now, the number of terminators that can be evaluated before we throw a resource
    /// exhuastion error.
    ///
    /// Setting this to `0` disables the limit and allows the interpreter to run forever.
    pub steps_remaining: usize,
}

#[derive(Copy, Clone, Debug)]
pub struct MemoryExtra {
    /// Whether this machine may read from statics
    pub(super) can_access_statics: bool,
}

impl CompileTimeInterpreter {
    pub(super) fn new(const_eval_limit: usize) -> Self {
        CompileTimeInterpreter { steps_remaining: const_eval_limit }
    }
}

impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
    #[inline(always)]
    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
    where
        K: Borrow<Q>,
    {
        FxHashMap::contains_key(self, k)
    }

    #[inline(always)]
    fn insert(&mut self, k: K, v: V) -> Option<V> {
        FxHashMap::insert(self, k, v)
    }

    #[inline(always)]
    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
    where
        K: Borrow<Q>,
    {
        FxHashMap::remove(self, k)
    }

    #[inline(always)]
    fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
        self.iter().filter_map(move |(k, v)| f(k, &*v)).collect()
    }

    #[inline(always)]
    fn get_or<E>(&self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Result<&V, E> {
        match self.get(&k) {
            Some(v) => Ok(v),
            None => {
                vacant()?;
                bug!("The CTFE machine shouldn't ever need to extend the alloc_map when reading")
            }
        }
    }

    #[inline(always)]
    fn get_mut_or<E>(&mut self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Result<&mut V, E> {
        match self.entry(k) {
            Entry::Occupied(e) => Ok(e.into_mut()),
            Entry::Vacant(e) => {
                let v = vacant()?;
                Ok(e.insert(v))
            }
        }
    }
}

crate type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter>;

impl interpret::MayLeak for ! {
    #[inline(always)]
    fn may_leak(self) -> bool {
        // `self` is uninhabited
        self
    }
}

impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter {
    type MemoryKind = !;
    type PointerTag = ();
    type ExtraFnVal = !;

    type FrameExtra = ();
    type MemoryExtra = MemoryExtra;
    type AllocExtra = ();

    type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>;

    const GLOBAL_KIND: Option<!> = None; // no copying of globals from `tcx` to machine memory

    #[inline(always)]
    fn enforce_alignment(_memory_extra: &Self::MemoryExtra) -> bool {
        // We do not check for alignment to avoid having to carry an `Align`
        // in `ConstValue::ByRef`.
        false
    }

    #[inline(always)]
    fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
        false // for now, we don't enforce validity
    }

    fn find_mir_or_eval_fn(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx>],
        ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
        _unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts
    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
        debug!("find_mir_or_eval_fn: {:?}", instance);

        // Only check non-glue functions
        if let ty::InstanceDef::Item(def_id) = instance.def {
            // Execution might have wandered off into other crates, so we cannot do a stability-
            // sensitive check here.  But we can at least rule out functions that are not const
            // at all.
            if ecx.tcx.is_const_fn_raw(def_id) {
                // If this function is a `const fn` then under certain circumstances we
                // can evaluate call via the query system, thus memoizing all future calls.
                if ecx.try_eval_const_fn_call(instance, ret, args)? {
                    return Ok(None);
                }
            } else {
                // Some functions we support even if they are non-const -- but avoid testing
                // that for const fn!
                ecx.hook_panic_fn(instance, args)?;
                // We certainly do *not* want to actually call the fn
                // though, so be sure we return here.
                throw_unsup_format!("calling non-const function `{}`", instance)
            }
        }
        // This is a const fn. Call it.
        Ok(Some(match ecx.load_mir(instance.def, None) {
            Ok(body) => *body,
            Err(err) => {
                if let err_unsup!(NoMirFor(did)) = err.kind {
                    let path = ecx.tcx.def_path_str(did);
                    return Err(ConstEvalErrKind::NeedsRfc(format!(
                        "calling extern function `{}`",
                        path
                    ))
                    .into());
                }
                return Err(err);
            }
        }))
    }

    fn call_extra_fn(
        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
        fn_val: !,
        _args: &[OpTy<'tcx>],
        _ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
        _unwind: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx> {
        match fn_val {}
    }

    fn call_intrinsic(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx>],
        ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
        _unwind: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx> {
        if ecx.emulate_intrinsic(instance, args, ret)? {
            return Ok(());
        }
        // An intrinsic that we do not support
        let intrinsic_name = ecx.tcx.item_name(instance.def_id());
        Err(ConstEvalErrKind::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into())
    }

    fn assert_panic(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        msg: &AssertMessage<'tcx>,
        _unwind: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx> {
        use rustc_middle::mir::AssertKind::*;
        // Convert `AssertKind<Operand>` to `AssertKind<u64>`.
        let err = match msg {
            BoundsCheck { ref len, ref index } => {
                let len = ecx
                    .read_immediate(ecx.eval_operand(len, None)?)
                    .expect("can't eval len")
                    .to_scalar()?
                    .to_machine_usize(&*ecx)?;
                let index = ecx
                    .read_immediate(ecx.eval_operand(index, None)?)
                    .expect("can't eval index")
                    .to_scalar()?
                    .to_machine_usize(&*ecx)?;
                BoundsCheck { len, index }
            }
            Overflow(op) => Overflow(*op),
            OverflowNeg => OverflowNeg,
            DivisionByZero => DivisionByZero,
            RemainderByZero => RemainderByZero,
            ResumedAfterReturn(generator_kind) => ResumedAfterReturn(*generator_kind),
            ResumedAfterPanic(generator_kind) => ResumedAfterPanic(*generator_kind),
        };
        Err(ConstEvalErrKind::AssertFailure(err).into())
    }

    fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> {
        Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into())
    }

    fn binary_ptr_op(
        _ecx: &InterpCx<'mir, 'tcx, Self>,
        _bin_op: mir::BinOp,
        _left: ImmTy<'tcx>,
        _right: ImmTy<'tcx>,
    ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
        Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
    }

    #[inline(always)]
    fn init_allocation_extra<'b>(
        _memory_extra: &MemoryExtra,
        _id: AllocId,
        alloc: Cow<'b, Allocation>,
        _kind: Option<MemoryKind<!>>,
    ) -> (Cow<'b, Allocation<Self::PointerTag>>, Self::PointerTag) {
        // We do not use a tag so we can just cheaply forward the allocation
        (alloc, ())
    }

    #[inline(always)]
    fn tag_global_base_pointer(_memory_extra: &MemoryExtra, _id: AllocId) -> Self::PointerTag {}

    fn box_alloc(
        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
        _dest: PlaceTy<'tcx>,
    ) -> InterpResult<'tcx> {
        Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into())
    }

    fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
        // The step limit has already been hit in a previous call to `before_terminator`.
        if ecx.machine.steps_remaining == 0 {
            return Ok(());
        }

        ecx.machine.steps_remaining -= 1;
        if ecx.machine.steps_remaining == 0 {
            throw_exhaust!(StepLimitReached)
        }

        Ok(())
    }

    #[inline(always)]
    fn stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
        Ok(())
    }

    fn before_access_global(
        memory_extra: &MemoryExtra,
        alloc_id: AllocId,
        allocation: &Allocation,
        static_def_id: Option<DefId>,
        is_write: bool,
    ) -> InterpResult<'tcx> {
        if is_write {
            // Write access. These are never allowed, but we give a targeted error message.
            if allocation.mutability == Mutability::Not {
                Err(err_ub!(WriteToReadOnly(alloc_id)).into())
            } else {
                Err(ConstEvalErrKind::ModifiedGlobal.into())
            }
        } else {
            // Read access. These are usually allowed, with some exceptions.
            if memory_extra.can_access_statics {
                // Machine configuration allows us read from anything (e.g., `static` initializer).
                Ok(())
            } else if static_def_id.is_some() {
                // Machine configuration does not allow us to read statics
                // (e.g., `const` initializer).
                Err(ConstEvalErrKind::ConstAccessesStatic.into())
            } else {
                // Immutable global, this read is fine.
                // But make sure we never accept a read from something mutable, that would be
                // unsound. The reason is that as the content of this allocation may be different
                // now and at run-time, so if we permit reading now we might return the wrong value.
                assert_eq!(allocation.mutability, Mutability::Not);
                Ok(())
            }
        }
    }
}

// Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups
// so we can end up having a file with just that impl, but for now, let's keep the impl discoverable
// at the bottom of this file.
<|endoftext|>


<commit_before>//! Resolves links in markdown documentation.

use std::iter::once;

use itertools::Itertools;
use url::Url;

use crate::{db::HirDatabase, Adt, AsName, Crate, Hygiene, ItemInNs, ModPath, ModuleDef};
use hir_def::{db::DefDatabase, resolver::Resolver};
use syntax::ast::Path;

pub fn resolve_doc_link<T: Resolvable + Clone, D: DefDatabase + HirDatabase>(
    db: &D,
    definition: &T,
    link_text: &str,
    link_target: &str,
) -> Option<(String, String)> {
    try_resolve_intra(db, definition, link_text, &link_target).or_else(|| {
        if let Some(definition) = definition.clone().try_into_module_def() {
            try_resolve_path(db, &definition, &link_target)
                .map(|target| (target, link_text.to_string()))
        } else {
            None
        }
    })
}

/// Try to resolve path to local documentation via intra-doc-links (i.e. `super::gateway::Shard`).
///
/// See [RFC1946](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md).
fn try_resolve_intra<T: Resolvable, D: DefDatabase + HirDatabase>(
    db: &D,
    definition: &T,
    link_text: &str,
    link_target: &str,
) -> Option<(String, String)> {
    // Set link_target for implied shortlinks
    let link_target =
        if link_target.is_empty() { link_text.trim_matches('`') } else { link_target };

    let doclink = IntraDocLink::from(link_target);

    // Parse link as a module path
    let path = Path::parse(doclink.path).ok()?;
    let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap();

    // Resolve it relative to symbol's location (according to the RFC this should consider small scopes)
    let resolver = definition.resolver(db)?;

    let resolved = resolver.resolve_module_path_in_items(db, &modpath);
    let (defid, namespace) = match doclink.namespace {
        // FIXME: .or(resolved.macros)
        None => resolved
            .types
            .map(|t| (t.0, Namespace::Types))
            .or(resolved.values.map(|t| (t.0, Namespace::Values)))?,
        Some(ns @ Namespace::Types) => (resolved.types?.0, ns),
        Some(ns @ Namespace::Values) => (resolved.values?.0, ns),
        // FIXME:
        Some(Namespace::Macros) => None?,
    };

    // Get the filepath of the final symbol
    let def: ModuleDef = defid.into();
    let module = def.module(db)?;
    let krate = module.krate();
    let ns = match namespace {
        Namespace::Types => ItemInNs::Types(defid),
        Namespace::Values => ItemInNs::Values(defid),
        // FIXME:
        Namespace::Macros => None?,
    };
    let import_map = db.import_map(krate.into());
    let path = import_map.path_of(ns)?;

    Some((
        get_doc_url(db, &krate)?
            .join(&format!("{}/", krate.display_name(db)?))
            .ok()?
            .join(&path.segments.iter().map(|name| name.to_string()).join("/"))
            .ok()?
            .join(&get_symbol_filename(db, &def)?)
            .ok()?
            .into_string(),
        strip_prefixes_suffixes(link_text).to_string(),
    ))
}

/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`).
fn try_resolve_path(db: &dyn HirDatabase, moddef: &ModuleDef, link_target: &str) -> Option<String> {
    if !link_target.contains("#") && !link_target.contains(".html") {
        return None;
    }
    let ns = ItemInNs::Types(moddef.clone().into());

    let module = moddef.module(db)?;
    let krate = module.krate();
    let import_map = db.import_map(krate.into());
    let base = once(format!("{}", krate.display_name(db)?))
        .chain(import_map.path_of(ns)?.segments.iter().map(|name| format!("{}", name)))
        .join("/");

    get_doc_url(db, &krate)
        .and_then(|url| url.join(&base).ok())
        .and_then(|url| {
            get_symbol_filename(db, moddef).as_deref().map(|f| url.join(f).ok()).flatten()
        })
        .and_then(|url| url.join(link_target).ok())
        .map(|url| url.into_string())
}

/// Strip prefixes, suffixes, and inline code marks from the given string.
fn strip_prefixes_suffixes(mut s: &str) -> &str {
    s = s.trim_matches('`');

    [
        (TYPES.0.iter(), TYPES.1.iter()),
        (VALUES.0.iter(), VALUES.1.iter()),
        (MACROS.0.iter(), MACROS.1.iter()),
    ]
    .iter()
    .for_each(|(prefixes, suffixes)| {
        prefixes.clone().for_each(|prefix| s = s.trim_start_matches(*prefix));
        suffixes.clone().for_each(|suffix| s = s.trim_end_matches(*suffix));
    });
    let s = s.trim_start_matches("@").trim();
    s
}

fn get_doc_url(db: &dyn HirDatabase, krate: &Crate) -> Option<Url> {
    krate
        .get_html_root_url(db)
        .or_else(||
        // Fallback to docs.rs
        // FIXME: Specify an exact version here. This may be difficult, as multiple versions of the same crate could exist.
        Some(format!("https://docs.rs/{}/*/", krate.display_name(db)?)))
        .and_then(|s| Url::parse(&s).ok())
}

/// Get the filename and extension generated for a symbol by rustdoc.
///
/// Example: `struct.Shard.html`
fn get_symbol_filename(db: &dyn HirDatabase, definition: &ModuleDef) -> Option<String> {
    Some(match definition {
        ModuleDef::Adt(adt) => match adt {
            Adt::Struct(s) => format!("struct.{}.html", s.name(db)),
            Adt::Enum(e) => format!("enum.{}.html", e.name(db)),
            Adt::Union(u) => format!("union.{}.html", u.name(db)),
        },
        ModuleDef::Module(_) => "index.html".to_string(),
        ModuleDef::Trait(t) => format!("trait.{}.html", t.name(db)),
        ModuleDef::TypeAlias(t) => format!("type.{}.html", t.name(db)),
        ModuleDef::BuiltinType(t) => format!("primitive.{}.html", t.as_name()),
        ModuleDef::Function(f) => format!("fn.{}.html", f.name(db)),
        ModuleDef::EnumVariant(ev) => {
            format!("enum.{}.html#variant.{}", ev.parent_enum(db).name(db), ev.name(db))
        }
        ModuleDef::Const(c) => format!("const.{}.html", c.name(db)?),
        ModuleDef::Static(s) => format!("static.{}.html", s.name(db)?),
    })
}

struct IntraDocLink<'s> {
    path: &'s str,
    namespace: Option<Namespace>,
}

impl<'s> From<&'s str> for IntraDocLink<'s> {
    fn from(s: &'s str) -> Self {
        Self { path: strip_prefixes_suffixes(s), namespace: Namespace::from_intra_spec(s) }
    }
}

#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
enum Namespace {
    Types,
    Values,
    Macros,
}

static TYPES: ([&str; 7], [&str; 0]) =
    (["type", "struct", "enum", "mod", "trait", "union", "module"], []);
static VALUES: ([&str; 8], [&str; 1]) =
    (["value", "function", "fn", "method", "const", "static", "mod", "module"], ["()"]);
static MACROS: ([&str; 1], [&str; 1]) = (["macro"], ["!"]);

impl Namespace {
    /// Extract the specified namespace from an intra-doc-link if one exists.
    ///
    /// # Examples
    ///
    /// * `struct MyStruct` -> `Namespace::Types`
    /// * `panic!` -> `Namespace::Macros`
    /// * `fn@from_intra_spec` -> `Namespace::Values`
    fn from_intra_spec(s: &str) -> Option<Self> {
        [
            (Namespace::Types, (TYPES.0.iter(), TYPES.1.iter())),
            (Namespace::Values, (VALUES.0.iter(), VALUES.1.iter())),
            (Namespace::Macros, (MACROS.0.iter(), MACROS.1.iter())),
        ]
        .iter()
        .filter(|(_ns, (prefixes, suffixes))| {
            prefixes
                .clone()
                .map(|prefix| {
                    s.starts_with(*prefix)
                        && s.chars()
                            .nth(prefix.len() + 1)
                            .map(|c| c == '@' || c == ' ')
                            .unwrap_or(false)
                })
                .any(|cond| cond)
                || suffixes
                    .clone()
                    .map(|suffix| {
                        s.starts_with(*suffix)
                            && s.chars()
                                .nth(suffix.len() + 1)
                                .map(|c| c == '@' || c == ' ')
                                .unwrap_or(false)
                    })
                    .any(|cond| cond)
        })
        .map(|(ns, (_, _))| *ns)
        .next()
    }
}

/// Sealed trait used solely for the generic bound on [`resolve_doc_link`].
pub trait Resolvable {
    fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver>;
    fn try_into_module_def(self) -> Option<ModuleDef>;
}
<commit_msg>Minor<commit_after>//! Resolves links in markdown documentation.

use std::iter::once;

use hir_def::{db::DefDatabase, resolver::Resolver};
use itertools::Itertools;
use syntax::ast::Path;
use url::Url;

use crate::{db::HirDatabase, Adt, AsName, Crate, Hygiene, ItemInNs, ModPath, ModuleDef};

pub fn resolve_doc_link<T: Resolvable + Clone, D: DefDatabase + HirDatabase>(
    db: &D,
    definition: &T,
    link_text: &str,
    link_target: &str,
) -> Option<(String, String)> {
    try_resolve_intra(db, definition, link_text, &link_target).or_else(|| {
        let definition = definition.clone().try_into_module_def()?;
        try_resolve_path(db, &definition, &link_target)
            .map(|target| (target, link_text.to_string()))
    })
}

/// Try to resolve path to local documentation via intra-doc-links (i.e. `super::gateway::Shard`).
///
/// See [RFC1946](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md).
fn try_resolve_intra<T: Resolvable, D: DefDatabase + HirDatabase>(
    db: &D,
    definition: &T,
    link_text: &str,
    link_target: &str,
) -> Option<(String, String)> {
    // Set link_target for implied shortlinks
    let link_target =
        if link_target.is_empty() { link_text.trim_matches('`') } else { link_target };

    let doclink = IntraDocLink::from(link_target);

    // Parse link as a module path
    let path = Path::parse(doclink.path).ok()?;
    let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap();

    // Resolve it relative to symbol's location (according to the RFC this should consider small scopes)
    let resolver = definition.resolver(db)?;

    let resolved = resolver.resolve_module_path_in_items(db, &modpath);
    let (defid, namespace) = match doclink.namespace {
        // FIXME: .or(resolved.macros)
        None => resolved
            .types
            .map(|t| (t.0, Namespace::Types))
            .or(resolved.values.map(|t| (t.0, Namespace::Values)))?,
        Some(ns @ Namespace::Types) => (resolved.types?.0, ns),
        Some(ns @ Namespace::Values) => (resolved.values?.0, ns),
        // FIXME:
        Some(Namespace::Macros) => return None,
    };

    // Get the filepath of the final symbol
    let def: ModuleDef = defid.into();
    let module = def.module(db)?;
    let krate = module.krate();
    let ns = match namespace {
        Namespace::Types => ItemInNs::Types(defid),
        Namespace::Values => ItemInNs::Values(defid),
        // FIXME:
        Namespace::Macros => None?,
    };
    let import_map = db.import_map(krate.into());
    let path = import_map.path_of(ns)?;

    Some((
        get_doc_url(db, &krate)?
            .join(&format!("{}/", krate.display_name(db)?))
            .ok()?
            .join(&path.segments.iter().map(|name| name.to_string()).join("/"))
            .ok()?
            .join(&get_symbol_filename(db, &def)?)
            .ok()?
            .into_string(),
        strip_prefixes_suffixes(link_text).to_string(),
    ))
}

/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`).
fn try_resolve_path(db: &dyn HirDatabase, moddef: &ModuleDef, link_target: &str) -> Option<String> {
    if !link_target.contains("#") && !link_target.contains(".html") {
        return None;
    }
    let ns = ItemInNs::Types(moddef.clone().into());

    let module = moddef.module(db)?;
    let krate = module.krate();
    let import_map = db.import_map(krate.into());
    let base = once(format!("{}", krate.display_name(db)?))
        .chain(import_map.path_of(ns)?.segments.iter().map(|name| format!("{}", name)))
        .join("/");

    get_doc_url(db, &krate)
        .and_then(|url| url.join(&base).ok())
        .and_then(|url| {
            get_symbol_filename(db, moddef).as_deref().map(|f| url.join(f).ok()).flatten()
        })
        .and_then(|url| url.join(link_target).ok())
        .map(|url| url.into_string())
}

/// Strip prefixes, suffixes, and inline code marks from the given string.
fn strip_prefixes_suffixes(mut s: &str) -> &str {
    s = s.trim_matches('`');

    [
        (TYPES.0.iter(), TYPES.1.iter()),
        (VALUES.0.iter(), VALUES.1.iter()),
        (MACROS.0.iter(), MACROS.1.iter()),
    ]
    .iter()
    .for_each(|(prefixes, suffixes)| {
        prefixes.clone().for_each(|prefix| s = s.trim_start_matches(*prefix));
        suffixes.clone().for_each(|suffix| s = s.trim_end_matches(*suffix));
    });
    let s = s.trim_start_matches("@").trim();
    s
}

fn get_doc_url(db: &dyn HirDatabase, krate: &Crate) -> Option<Url> {
    krate
        .get_html_root_url(db)
        .or_else(||
        // Fallback to docs.rs
        // FIXME: Specify an exact version here. This may be difficult, as multiple versions of the same crate could exist.
        Some(format!("https://docs.rs/{}/*/", krate.display_name(db)?)))
        .and_then(|s| Url::parse(&s).ok())
}

/// Get the filename and extension generated for a symbol by rustdoc.
///
/// Example: `struct.Shard.html`
fn get_symbol_filename(db: &dyn HirDatabase, definition: &ModuleDef) -> Option<String> {
    Some(match definition {
        ModuleDef::Adt(adt) => match adt {
            Adt::Struct(s) => format!("struct.{}.html", s.name(db)),
            Adt::Enum(e) => format!("enum.{}.html", e.name(db)),
            Adt::Union(u) => format!("union.{}.html", u.name(db)),
        },
        ModuleDef::Module(_) => "index.html".to_string(),
        ModuleDef::Trait(t) => format!("trait.{}.html", t.name(db)),
        ModuleDef::TypeAlias(t) => format!("type.{}.html", t.name(db)),
        ModuleDef::BuiltinType(t) => format!("primitive.{}.html", t.as_name()),
        ModuleDef::Function(f) => format!("fn.{}.html", f.name(db)),
        ModuleDef::EnumVariant(ev) => {
            format!("enum.{}.html#variant.{}", ev.parent_enum(db).name(db), ev.name(db))
        }
        ModuleDef::Const(c) => format!("const.{}.html", c.name(db)?),
        ModuleDef::Static(s) => format!("static.{}.html", s.name(db)?),
    })
}

struct IntraDocLink<'s> {
    path: &'s str,
    namespace: Option<Namespace>,
}

impl<'s> From<&'s str> for IntraDocLink<'s> {
    fn from(s: &'s str) -> Self {
        Self { path: strip_prefixes_suffixes(s), namespace: Namespace::from_intra_spec(s) }
    }
}

#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
enum Namespace {
    Types,
    Values,
    Macros,
}

static TYPES: ([&str; 7], [&str; 0]) =
    (["type", "struct", "enum", "mod", "trait", "union", "module"], []);
static VALUES: ([&str; 8], [&str; 1]) =
    (["value", "function", "fn", "method", "const", "static", "mod", "module"], ["()"]);
static MACROS: ([&str; 1], [&str; 1]) = (["macro"], ["!"]);

impl Namespace {
    /// Extract the specified namespace from an intra-doc-link if one exists.
    ///
    /// # Examples
    ///
    /// * `struct MyStruct` -> `Namespace::Types`
    /// * `panic!` -> `Namespace::Macros`
    /// * `fn@from_intra_spec` -> `Namespace::Values`
    fn from_intra_spec(s: &str) -> Option<Self> {
        [
            (Namespace::Types, (TYPES.0.iter(), TYPES.1.iter())),
            (Namespace::Values, (VALUES.0.iter(), VALUES.1.iter())),
            (Namespace::Macros, (MACROS.0.iter(), MACROS.1.iter())),
        ]
        .iter()
        .filter(|(_ns, (prefixes, suffixes))| {
            prefixes
                .clone()
                .map(|prefix| {
                    s.starts_with(*prefix)
                        && s.chars()
                            .nth(prefix.len() + 1)
                            .map(|c| c == '@' || c == ' ')
                            .unwrap_or(false)
                })
                .any(|cond| cond)
                || suffixes
                    .clone()
                    .map(|suffix| {
                        s.starts_with(*suffix)
                            && s.chars()
                                .nth(suffix.len() + 1)
                                .map(|c| c == '@' || c == ' ')
                                .unwrap_or(false)
                    })
                    .any(|cond| cond)
        })
        .map(|(ns, (_, _))| *ns)
        .next()
    }
}

/// Sealed trait used solely for the generic bound on [`resolve_doc_link`].
pub trait Resolvable {
    fn resolver<D: DefDatabase + HirDatabase>(&self, db: &D) -> Option<Resolver>;
    fn try_into_module_def(self) -> Option<ModuleDef>;
}
<|endoftext|>


<commit_before>/// A simple wait-free, grow-only pagetable, assumes a dense keyspace.
extern crate sled_sync;

use std::sync::atomic::Ordering::SeqCst;

use sled_sync::{
    debug_delay, pin, unprotected, Atomic, Guard, Owned, Shared,
};

const FANFACTOR: usize = 18;
const FANOUT: usize = 1 << FANFACTOR;
const FAN_MASK: usize = FANOUT - 1;

pub type PageId = usize;

macro_rules! rep_no_copy {
    ($e:expr; $n:expr) => {{
        let mut v = Vec::with_capacity($n);

        for _ in 0..$n {
            v.push($e);
        }

        v
    }};
}

#[inline(always)]
fn split_fanout(i: usize) -> (usize, usize) {
    // right shift 32 on 32-bit pointer systems panics
    #[cfg(target_pointer_width = "64")]
    assert!(i <= 1 << (FANFACTOR * 2));

    let left = i >> FANFACTOR;
    let right = i & FAN_MASK;
    (left, right)
}

struct Node1<T: Send + 'static> {
    children: Vec<Atomic<Node2<T>>>,
}

struct Node2<T: Send + 'static> {
    children: Vec<Atomic<T>>,
}

impl<T: Send + 'static> Default for Node1<T> {
    fn default() -> Node1<T> {
        let children = rep_no_copy!(Atomic::null(); FANOUT);
        Node1 { children: children }
    }
}

impl<T: Send + 'static> Default for Node2<T> {
    fn default() -> Node2<T> {
        let children = rep_no_copy!(Atomic::null(); FANOUT);
        Node2 { children: children }
    }
}

/// A simple lock-free radix tree.
pub struct PageTable<T>
where
    T: 'static + Send + Sync,
{
    head: Atomic<Node1<T>>,
}

impl<T> Default for PageTable<T>
where
    T: 'static + Send + Sync,
{
    fn default() -> PageTable<T> {
        let head = Owned::new(Node1::default());
        PageTable {
            head: Atomic::from(head),
        }
    }
}

impl<T> PageTable<T>
where
    T: 'static + Send + Sync,
{
    /// Atomically swap the previous value in a tree with a new one.
    pub fn swap<'g>(
        &self,
        pid: PageId,
        new: Shared<'g, T>,
        guard: &'g Guard,
    ) -> Shared<'g, T> {
        let tip = traverse(self.head.load(SeqCst, guard), pid, guard);
        debug_delay();
        tip.swap(new, SeqCst, guard)
    }

    /// Compare and swap an old value to a new one.
    pub fn cas<'g>(
        &self,
        pid: PageId,
        old: Shared<'g, T>,
        new: Shared<'g, T>,
        guard: &'g Guard,
    ) -> Result<Shared<'g, T>, Shared<'g, T>> {
        debug_delay();
        let tip = traverse(self.head.load(SeqCst, guard), pid, guard);

        debug_delay();

        match tip.compare_and_set(old, new, SeqCst, guard) {
            Ok(_) => {
                if !old.is_null() {
                    unsafe {
                        let old_owned = old.into_owned();
                        guard.defer(move || old_owned);
                    }
                }
                Ok(new)
            }
            Err(e) => Err(e.current),
        }
    }

    /// Try to get a value from the tree.
    pub fn get<'g>(
        &self,
        pid: PageId,
        guard: &'g Guard,
    ) -> Option<Shared<'g, T>> {
        debug_delay();
        let tip = traverse(self.head.load(SeqCst, guard), pid, guard);
        if tip.load(SeqCst, guard).is_null() {
            return None;
        }
        let res = tip.load(SeqCst, guard);
        if res.is_null() {
            None
        } else {
            Some(res)
        }
    }

    /// Delete a value from the tree, returning the old value if it was set.
    pub fn del<'g>(
        &self,
        pid: PageId,
        guard: &'g Guard,
    ) -> Option<Shared<'g, T>> {
        debug_delay();
        let old = self.swap(pid, Shared::null(), guard);
        if !old.is_null() {
            unsafe {
                let old_owned = old.into_owned();
                guard.defer(move || old_owned);
            }
            Some(old)
        } else {
            None
        }
    }
}

fn traverse<'g, T: 'static + Send>(
    head: Shared<'g, Node1<T>>,
    k: PageId,
    guard: &'g Guard,
) -> &'g Atomic<T> {
    let (l1k, l2k) = split_fanout(k);

    debug_delay();
    let l1 = unsafe { &head.deref().children };

    debug_delay();
    let mut l2_ptr = l1[l1k].load(SeqCst, guard);

    if l2_ptr.is_null() {
        let next_child =
            Owned::new(Node2::default()).into_shared(guard);

        debug_delay();
        let ret = l1[l1k]
            .compare_and_set(l2_ptr, next_child, SeqCst, guard);

        match ret {
            Ok(_) => {
                // CAS worked
                l2_ptr = next_child;
            }
            Err(e) => {
                // another thread beat us, drop unused created
                // child and use what is already set
                l2_ptr = e.current;
            }
        }
    }

    debug_delay();
    let l2 = unsafe { &l2_ptr.deref().children };

    &l2[l2k]
}

impl<T> Drop for PageTable<T>
where
    T: 'static + Send + Sync,
{
    fn drop(&mut self) {
        unsafe {
            let head = self.head.load(SeqCst, unprotected()).as_raw();
            drop(Box::from_raw(head as *mut Node1<T>));
        }
    }
}

impl<T: Send + 'static> Drop for Node1<T> {
    fn drop(&mut self) {
        unsafe {
            let guard = pin();
            let children: Vec<*const Node2<T>> = self
                .children
                .iter()
                .map(|c| c.load(SeqCst, &guard).as_raw())
                .filter(|c| !c.is_null())
                .collect();

            for child in children {
                drop(Box::from_raw(child as *mut Node2<T>));
            }
        }
    }
}

impl<T: Send + 'static> Drop for Node2<T> {
    fn drop(&mut self) {
        unsafe {
            let guard = pin();

            let children: Vec<*const T> = self
                .children
                .iter()
                .map(|c| c.load(SeqCst, &guard).as_raw())
                .filter(|c| !c.is_null())
                .collect();

            for child in children {
                drop(Box::from_raw(child as *mut T));
            }
        }
    }
}

#[test]
fn test_split_fanout() {
    assert_eq!(split_fanout(0b11_1111_1111_1111_1111), (0, 0b11_1111_1111_1111_1111));
    assert_eq!(split_fanout(0b111_1111_1111_1111_1111), (0b1, 0b11_1111_1111_1111_1111));
}

#[test]
fn basic_functionality() {
    unsafe {
        let guard = pin();
        let rt = PageTable::default();
        let v1 = Owned::new(5).into_shared(&guard);
        rt.cas(0, Shared::null(), v1, &guard).unwrap();
        let ptr = rt.get(0, &guard).unwrap();
        assert_eq!(ptr.deref(), &5);
        rt.cas(0, ptr, Owned::new(6).into_shared(&guard), &guard)
            .unwrap();
        assert_eq!(rt.get(0, &guard).unwrap().deref(), &6);
        rt.del(0, &guard);
        assert!(rt.get(0, &guard).is_none());

        let k2 = 321 << FANFACTOR;
        let k3 = k2 + 1;

        let v2 = Owned::new(2).into_shared(&guard);
        rt.cas(k2, Shared::null(), v2, &guard).unwrap();
        assert_eq!(rt.get(k2, &guard).unwrap().deref(), &2);
        assert!(rt.get(k3, &guard).is_none());
        let v3 = Owned::new(3).into_shared(&guard);
        rt.cas(k3, Shared::null(), v3, &guard).unwrap();
        assert_eq!(rt.get(k3, &guard).unwrap().deref(), &3);
        assert_eq!(rt.get(k2, &guard).unwrap().deref(), &2);
    }
}
<commit_msg>Remove redundant load operation on the 2mb page<commit_after>/// A simple wait-free, grow-only pagetable, assumes a dense keyspace.
extern crate sled_sync;

use std::sync::atomic::Ordering::SeqCst;

use sled_sync::{
    debug_delay, pin, unprotected, Atomic, Guard, Owned, Shared,
};

const FANFACTOR: usize = 18;
const FANOUT: usize = 1 << FANFACTOR;
const FAN_MASK: usize = FANOUT - 1;

pub type PageId = usize;

macro_rules! rep_no_copy {
    ($e:expr; $n:expr) => {{
        let mut v = Vec::with_capacity($n);

        for _ in 0..$n {
            v.push($e);
        }

        v
    }};
}

#[inline(always)]
fn split_fanout(i: usize) -> (usize, usize) {
    // right shift 32 on 32-bit pointer systems panics
    #[cfg(target_pointer_width = "64")]
    assert!(i <= 1 << (FANFACTOR * 2));

    let left = i >> FANFACTOR;
    let right = i & FAN_MASK;
    (left, right)
}

struct Node1<T: Send + 'static> {
    children: Vec<Atomic<Node2<T>>>,
}

struct Node2<T: Send + 'static> {
    children: Vec<Atomic<T>>,
}

impl<T: Send + 'static> Default for Node1<T> {
    fn default() -> Node1<T> {
        let children = rep_no_copy!(Atomic::null(); FANOUT);
        Node1 { children: children }
    }
}

impl<T: Send + 'static> Default for Node2<T> {
    fn default() -> Node2<T> {
        let children = rep_no_copy!(Atomic::null(); FANOUT);
        Node2 { children: children }
    }
}

/// A simple lock-free radix tree.
pub struct PageTable<T>
where
    T: 'static + Send + Sync,
{
    head: Atomic<Node1<T>>,
}

impl<T> Default for PageTable<T>
where
    T: 'static + Send + Sync,
{
    fn default() -> PageTable<T> {
        let head = Owned::new(Node1::default());
        PageTable {
            head: Atomic::from(head),
        }
    }
}

impl<T> PageTable<T>
where
    T: 'static + Send + Sync,
{
    /// Atomically swap the previous value in a tree with a new one.
    pub fn swap<'g>(
        &self,
        pid: PageId,
        new: Shared<'g, T>,
        guard: &'g Guard,
    ) -> Shared<'g, T> {
        let tip = traverse(self.head.load(SeqCst, guard), pid, guard);
        debug_delay();
        tip.swap(new, SeqCst, guard)
    }

    /// Compare and swap an old value to a new one.
    pub fn cas<'g>(
        &self,
        pid: PageId,
        old: Shared<'g, T>,
        new: Shared<'g, T>,
        guard: &'g Guard,
    ) -> Result<Shared<'g, T>, Shared<'g, T>> {
        debug_delay();
        let tip = traverse(self.head.load(SeqCst, guard), pid, guard);

        debug_delay();

        match tip.compare_and_set(old, new, SeqCst, guard) {
            Ok(_) => {
                if !old.is_null() {
                    unsafe {
                        let old_owned = old.into_owned();
                        guard.defer(move || old_owned);
                    }
                }
                Ok(new)
            }
            Err(e) => Err(e.current),
        }
    }

    /// Try to get a value from the tree.
    pub fn get<'g>(
        &self,
        pid: PageId,
        guard: &'g Guard,
    ) -> Option<Shared<'g, T>> {
        debug_delay();
        let tip = traverse(self.head.load(SeqCst, guard), pid, guard);

        let res = tip.load(SeqCst, guard);
        if res.is_null() {
            None
        } else {
            Some(res)
        }
    }

    /// Delete a value from the tree, returning the old value if it was set.
    pub fn del<'g>(
        &self,
        pid: PageId,
        guard: &'g Guard,
    ) -> Option<Shared<'g, T>> {
        debug_delay();
        let old = self.swap(pid, Shared::null(), guard);
        if !old.is_null() {
            unsafe {
                let old_owned = old.into_owned();
                guard.defer(move || old_owned);
            }
            Some(old)
        } else {
            None
        }
    }
}

fn traverse<'g, T: 'static + Send>(
    head: Shared<'g, Node1<T>>,
    k: PageId,
    guard: &'g Guard,
) -> &'g Atomic<T> {
    let (l1k, l2k) = split_fanout(k);

    debug_delay();
    let l1 = unsafe { &head.deref().children };

    debug_delay();
    let mut l2_ptr = l1[l1k].load(SeqCst, guard);

    if l2_ptr.is_null() {
        let next_child =
            Owned::new(Node2::default()).into_shared(guard);

        debug_delay();
        let ret = l1[l1k]
            .compare_and_set(l2_ptr, next_child, SeqCst, guard);

        match ret {
            Ok(_) => {
                // CAS worked
                l2_ptr = next_child;
            }
            Err(e) => {
                // another thread beat us, drop unused created
                // child and use what is already set
                l2_ptr = e.current;
            }
        }
    }

    debug_delay();
    let l2 = unsafe { &l2_ptr.deref().children };

    &l2[l2k]
}

impl<T> Drop for PageTable<T>
where
    T: 'static + Send + Sync,
{
    fn drop(&mut self) {
        unsafe {
            let head = self.head.load(SeqCst, unprotected()).as_raw();
            drop(Box::from_raw(head as *mut Node1<T>));
        }
    }
}

impl<T: Send + 'static> Drop for Node1<T> {
    fn drop(&mut self) {
        unsafe {
            let guard = pin();
            let children: Vec<*const Node2<T>> = self
                .children
                .iter()
                .map(|c| c.load(SeqCst, &guard).as_raw())
                .filter(|c| !c.is_null())
                .collect();

            for child in children {
                drop(Box::from_raw(child as *mut Node2<T>));
            }
        }
    }
}

impl<T: Send + 'static> Drop for Node2<T> {
    fn drop(&mut self) {
        unsafe {
            let guard = pin();

            let children: Vec<*const T> = self
                .children
                .iter()
                .map(|c| c.load(SeqCst, &guard).as_raw())
                .filter(|c| !c.is_null())
                .collect();

            for child in children {
                drop(Box::from_raw(child as *mut T));
            }
        }
    }
}

#[test]
fn test_split_fanout() {
    assert_eq!(split_fanout(0b11_1111_1111_1111_1111), (0, 0b11_1111_1111_1111_1111));
    assert_eq!(split_fanout(0b111_1111_1111_1111_1111), (0b1, 0b11_1111_1111_1111_1111));
}

#[test]
fn basic_functionality() {
    unsafe {
        let guard = pin();
        let rt = PageTable::default();
        let v1 = Owned::new(5).into_shared(&guard);
        rt.cas(0, Shared::null(), v1, &guard).unwrap();
        let ptr = rt.get(0, &guard).unwrap();
        assert_eq!(ptr.deref(), &5);
        rt.cas(0, ptr, Owned::new(6).into_shared(&guard), &guard)
            .unwrap();
        assert_eq!(rt.get(0, &guard).unwrap().deref(), &6);
        rt.del(0, &guard);
        assert!(rt.get(0, &guard).is_none());

        let k2 = 321 << FANFACTOR;
        let k3 = k2 + 1;

        let v2 = Owned::new(2).into_shared(&guard);
        rt.cas(k2, Shared::null(), v2, &guard).unwrap();
        assert_eq!(rt.get(k2, &guard).unwrap().deref(), &2);
        assert!(rt.get(k3, &guard).is_none());
        let v3 = Owned::new(3).into_shared(&guard);
        rt.cas(k3, Shared::null(), v3, &guard).unwrap();
        assert_eq!(rt.get(k3, &guard).unwrap().deref(), &3);
        assert_eq!(rt.get(k2, &guard).unwrap().deref(), &2);
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Seek, SeekFrom};
use byteorder::{BigEndian, ByteOrder};
use {HEADER_LEN, Error, Result};

/// A farbfeld decoder
#[derive(Debug)]
pub struct Decoder<R> {
    r: R,

    width: u32,
    height: u32,
}

impl<R: Read + Seek> Decoder<R> {
    /// Create a new decoder from `r` and parse the header.
    /// # Failures
    /// Returns FarbfeldError::FormatError if the magic number does not match `farbfeld`
    pub fn new(mut r: R) -> Result<Decoder<R>> {
        let head = &mut [0; HEADER_LEN as usize];
        r.seek(SeekFrom::Start(0))?;
        r.read_exact(head)?;
        if &head[..8] != b"farbfeld" {
                return Err(Error::FormatError("unexpected magic number".to_string()))
        }

        Ok(Decoder {
            r: r,
            width: BigEndian::read_u32(&head[8..]),
            height: BigEndian::read_u32(&head[12..]),
        })
    }

    /// Returns the `(width, height)` of the image.
    pub fn dimensions(&mut self) -> (u32, u32) {
        (self.width, self.height)
    }

    /// Returns the length in bytes for a row.
    pub fn row_len(&mut self) -> usize {
        self.width as usize * 8
    }

    /// Read a single row from the image and return the bytes read.
    /// # Failures
    /// Returns a `FarbfeldError::ImageEnd` if the `row` is greater as the `height`
    pub fn read_row(&mut self, row: u32,  buf: &mut [u8]) -> Result<usize> {
        if row > self.height { return Err(Error::ImageEnd) }

        let row_len = self.row_len();
        let offset = HEADER_LEN + row as u64 * row_len as u64;
        self.r.seek(SeekFrom::Start(offset))?;
        self.r.read_exact(&mut buf[..row_len])?;
        Ok(row_len)
    }

    /// Read whole image into a `Vec<u8>`.
    pub fn read_image(&mut self) -> Result<Vec<u8>> {
        self.r.seek(SeekFrom::Start(HEADER_LEN))?;
        let num_raw_bytes = self.height as usize * self.row_len();
        let mut buf = vec![0; num_raw_bytes];
        self.r.read_exact(&mut buf)?;
        Ok(buf)
    }
}

#[cfg(test)]
mod tests {
    use std::io::{Cursor, ErrorKind, Write};
    use Decoder;
    use tests::IMAGE_DATA;
    use Error;

    macro_rules! try_panic {
        ($e:expr) => {
            match $e {
                Err(e) => panic!(e),
                Ok(res) => res,
            }
        }
    }

    #[test]
    fn invalid_magic() {
        let mut img_data = Vec::new();
        try_panic!(img_data.write(b"test fail"));
        try_panic!(img_data.write(&IMAGE_DATA[8..]));
        let buf = Cursor::new(img_data);

        match Decoder::new(buf) {
            Err(e) => match e {
                Error::FormatError(_) => return,
                e => panic!("{:?}", e),
            },
            Ok(_) => panic!("Got Ok expected FarbfeldError::FormatError"),
        }
    }

    #[test]
    fn truncate_header() {
        let buf = Cursor::new(&IMAGE_DATA[0..8]);

        match Decoder::new(buf) {
            Err(Error::IoError(e)) => {
                if e.kind() == ErrorKind::UnexpectedEof {
                    return
                } else { panic!("{:?}", e) }
            },
            Err(e) => panic!("{:?}", e),
            Ok(_) => panic!("Got Ok expected FarbfeldError::FormatError"),
        }

    }

    #[test]
    fn truncate_data() {
        let mut img_data = Vec::with_capacity(IMAGE_DATA.len()-1);
        try_panic!(img_data.write_all(&IMAGE_DATA[..IMAGE_DATA.len()-1]));
        let buf = Cursor::new(img_data);
        let mut img = Decoder::new(buf).unwrap();
        match img.read_image() {
            Err(Error::IoError(e)) => {
                if e.kind() == ErrorKind::UnexpectedEof {
                    return
                } else { panic!("{:?}", e) }
            },
            Err(e) => panic!("{:?}", e),
            Ok(_) => panic!("Got Ok expected FarbfeldError::FormatError"),
        }
    }
}
<commit_msg>remove unnecessary mut from decoder methods<commit_after>use std::io::{Read, Seek, SeekFrom};
use byteorder::{BigEndian, ByteOrder};
use {HEADER_LEN, Error, Result};

/// A farbfeld decoder
#[derive(Debug)]
pub struct Decoder<R> {
    r: R,

    width: u32,
    height: u32,
}

impl<R: Read + Seek> Decoder<R> {
    /// Create a new decoder from `r` and parse the header.
    /// # Failures
    /// Returns FarbfeldError::FormatError if the magic number does not match `farbfeld`
    pub fn new(mut r: R) -> Result<Decoder<R>> {
        let head = &mut [0; HEADER_LEN as usize];
        r.seek(SeekFrom::Start(0))?;
        r.read_exact(head)?;
        if &head[..8] != b"farbfeld" {
                return Err(Error::FormatError("unexpected magic number".to_string()))
        }

        Ok(Decoder {
            r: r,
            width: BigEndian::read_u32(&head[8..]),
            height: BigEndian::read_u32(&head[12..]),
        })
    }

    /// Returns the `(width, height)` of the image.
    pub fn dimensions(&self) -> (u32, u32) {
        (self.width, self.height)
    }

    /// Returns the length in bytes for a row.
    pub fn row_len(&self) -> usize {
        self.width as usize * 8
    }

    /// Read a single row from the image and return the bytes read.
    /// # Failures
    /// Returns a `FarbfeldError::ImageEnd` if the `row` is greater as the `height`
    pub fn read_row(&mut self, row: u32,  buf: &mut [u8]) -> Result<usize> {
        if row > self.height { return Err(Error::ImageEnd) }

        let row_len = self.row_len();
        let offset = HEADER_LEN + row as u64 * row_len as u64;
        self.r.seek(SeekFrom::Start(offset))?;
        self.r.read_exact(&mut buf[..row_len])?;
        Ok(row_len)
    }

    /// Read whole image into a `Vec<u8>`.
    pub fn read_image(&mut self) -> Result<Vec<u8>> {
        self.r.seek(SeekFrom::Start(HEADER_LEN))?;
        let num_raw_bytes = self.height as usize * self.row_len();
        let mut buf = vec![0; num_raw_bytes];
        self.r.read_exact(&mut buf)?;
        Ok(buf)
    }
}

#[cfg(test)]
mod tests {
    use std::io::{Cursor, ErrorKind, Write};
    use Decoder;
    use tests::IMAGE_DATA;
    use Error;

    macro_rules! try_panic {
        ($e:expr) => {
            match $e {
                Err(e) => panic!(e),
                Ok(res) => res,
            }
        }
    }

    #[test]
    fn invalid_magic() {
        let mut img_data = Vec::new();
        try_panic!(img_data.write(b"test fail"));
        try_panic!(img_data.write(&IMAGE_DATA[8..]));
        let buf = Cursor::new(img_data);

        match Decoder::new(buf) {
            Err(e) => match e {
                Error::FormatError(_) => return,
                e => panic!("{:?}", e),
            },
            Ok(_) => panic!("Got Ok expected FarbfeldError::FormatError"),
        }
    }

    #[test]
    fn truncate_header() {
        let buf = Cursor::new(&IMAGE_DATA[0..8]);

        match Decoder::new(buf) {
            Err(Error::IoError(e)) => {
                if e.kind() == ErrorKind::UnexpectedEof {
                    return
                } else { panic!("{:?}", e) }
            },
            Err(e) => panic!("{:?}", e),
            Ok(_) => panic!("Got Ok expected FarbfeldError::FormatError"),
        }

    }

    #[test]
    fn truncate_data() {
        let mut img_data = Vec::with_capacity(IMAGE_DATA.len()-1);
        try_panic!(img_data.write_all(&IMAGE_DATA[..IMAGE_DATA.len()-1]));
        let buf = Cursor::new(img_data);
        let mut img = Decoder::new(buf).unwrap();
        match img.read_image() {
            Err(Error::IoError(e)) => {
                if e.kind() == ErrorKind::UnexpectedEof {
                    return
                } else { panic!("{:?}", e) }
            },
            Err(e) => panic!("{:?}", e),
            Ok(_) => panic!("Got Ok expected FarbfeldError::FormatError"),
        }
    }
}
<|endoftext|>


<commit_before>use sdl::Rect;
use sdl::video;

const SCALE: usize = 20;
const HEIGHT_BASE: usize = 32;
const WIDTH_BASE: usize = 64;

pub struct Display
{
    gfx: [[u8; WIDTH_BASE]; HEIGHT_BASE],
    draw_flag: bool,
    screen: video::Surface,
}

impl Display
{
    pub fn new() -> Display
    {
        Display {
            gfx: [[0; WIDTH_BASE]; HEIGHT_BASE],
            draw_flag: true,
            screen: video::set_video_mode((WIDTH_BASE * SCALE) as isize,
                                          (HEIGHT_BASE * SCALE) as isize,
                                          8,
                                          &[video::SurfaceFlag::HWSurface],
                                          &[video::VideoFlag::DoubleBuf])
                    .unwrap(),
        }
    }

    pub fn clear(&mut self)
    {
        self.gfx = [[0; WIDTH_BASE]; HEIGHT_BASE];
        self.draw_flag = true;
    }

    pub fn draw(&mut self, x: usize, y: usize, sprite: &[u8]) -> u8
    {
        let mut collision = 0u8;
        let n = sprite.len() as usize;
        let mut yj: usize;
        let mut xi: usize;

        for j in 0..n
        {
            for i in 0..8
            {
                yj = (y + j) % HEIGHT_BASE;
                xi = (x + i) % WIDTH_BASE;

                if (sprite[j] & (0x80 >> i)) != 0
                {
                    if self.gfx[yj][xi] == 1
                    {
                        collision = 1
                    }
                    self.gfx[yj][xi] ^= 1;
                }
            }
        }

        self.draw_flag = true;
        collision
    }

    pub fn draw_screen(&mut self)
    {
        if !self.draw_flag
        {
            return;
        }
        let mut pixel: u8;
        let sc = SCALE as u16;
        fn pt(p: usize) -> i16
        {
            (p as i16) * (SCALE as i16)
        }

        for y in 0..HEIGHT_BASE
        {
            for x in 0..WIDTH_BASE
            {
                pixel = if self.gfx[y][x] != 0 { 255 } else { 0 };
                self.screen.fill_rect(Some(Rect {
                                               x: pt(x),
                                               y: pt(y),
                                               w: sc,
                                               h: sc,
                                           }),
                                      video::RGB(pixel, pixel, pixel));
            }
        }

        self.screen.flip();
        self.draw_flag = false;
    }
}
<commit_msg>Small code prettification.<commit_after>use sdl::Rect;
use sdl::video;

const SCALE: usize = 20;
const HEIGHT_BASE: usize = 32;
const WIDTH_BASE: usize = 64;

pub struct Display
{
    gfx: [[u8; WIDTH_BASE]; HEIGHT_BASE],
    draw_flag: bool,
    screen: video::Surface,
}

impl Display
{
    pub fn new() -> Display
    {
        Display {
            gfx: [[0; WIDTH_BASE]; HEIGHT_BASE],
            draw_flag: true,
            screen: video::set_video_mode((WIDTH_BASE * SCALE) as isize,
                                          (HEIGHT_BASE * SCALE) as isize,
                                          8,
                                          &[video::SurfaceFlag::HWSurface],
                                          &[video::VideoFlag::DoubleBuf])
                    .unwrap(),
        }
    }

    pub fn clear(&mut self)
    {
        self.gfx = [[0; WIDTH_BASE]; HEIGHT_BASE];
        self.draw_flag = true;
    }

    pub fn draw(&mut self, x: usize, y: usize, sprite: &[u8]) -> u8
    {
        let mut collision = 0u8;
        let n = sprite.len() as usize;
        let mut yj: usize;
        let mut xi: usize;

        for j in 0..n
        {
            for i in 0..8
            {
                yj = (y + j) % HEIGHT_BASE;
                xi = (x + i) % WIDTH_BASE;

                if (sprite[j] & (0x80 >> i)) != 0
                {
                    if self.gfx[yj][xi] == 1
                    {
                        collision = 1
                    }
                    self.gfx[yj][xi] ^= 1;
                }
            }
        }

        self.draw_flag = true;
        collision
    }

    pub fn draw_screen(&mut self)
    {
        if !self.draw_flag
        {
            return;
        }

        let mut pixel: u8;

        for y in 0..HEIGHT_BASE
        {
            for x in 0..WIDTH_BASE
            {
                pixel = if self.gfx[y][x] != 0 { 255 } else { 0 };
                self.screen.fill_rect(Some(Rect {
                                               x: (x * SCALE) as i16,
                                               y: (y * SCALE) as i16,
                                               w: SCALE as u16,
                                               h: SCALE as u16,
                                           }),
                                      video::RGB(pixel, pixel, pixel));
            }
        }

        self.screen.flip();
        self.draw_flag = false;
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![allow(non_upper_case_globals)]

extern crate core_foundation;

use libc;
pub use base::{CGError, boolean_t};
pub use geometry::{CGRect, CGPoint, CGSize};

use image::CGImageRef;

pub type CGDirectDisplayID = libc::uint32_t;
pub type CGWindowID        = libc::uint32_t;

pub const kCGNullWindowID: CGWindowID = 0 as CGWindowID;

pub type CGWindowListOption = libc::uint32_t;

pub const kCGWindowListOptionAll:              CGWindowListOption    = 0;
pub const kCGWindowListOptionOnScreenOnly:     CGWindowListOption    = 1 << 0;
pub const kCGWindowListOptionOnScreenAboveWindow: CGWindowListOption = 1 << 1;
pub const kCGWindowListOptionOnScreenBelowWindow: CGWindowListOption = 1 << 2;
pub const kCGWindowListOptionIncludingWindow:  CGWindowListOption    = 1 << 3;
pub const kCGWindowListExcludeDesktopElements: CGWindowListOption    = 1 << 4;

pub type CGWindowImageOption = libc::uint32_t;

pub const kCGWindowImageDefault: CGWindowImageOption = 0;
pub const kCGWindowImageBoundsIgnoreFraming: CGWindowImageOption = 1 << 0;
pub const kCGWindowImageShouldBeOpaque: CGWindowImageOption = 1 << 1;
pub const kCGWindowImageOnlyShadows: CGWindowImageOption = 1 << 2;
pub const kCGWindowImageBestResolution: CGWindowImageOption = 1 << 3;
pub const kCGWindowImageNominalResolution: CGWindowImageOption = 1 << 4;

pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef, CFDictionaryGetValueIfPresent };
pub use core_foundation::array::{ CFArray, CFArrayRef };
pub use core_foundation::array::{ CFArrayGetCount, CFArrayGetValueAtIndex };
pub use core_foundation::base::{  CFIndex, CFRelease, CFTypeRef };

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    pub static CGRectNull: CGRect;
    pub static CGRectInfinite: CGRect;

    pub fn CGMainDisplayID() -> CGDirectDisplayID;
    pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double;
    pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize;
    pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGGetActiveDisplayList(max_displays: libc::uint32_t,
                                  active_displays: *mut CGDirectDisplayID,
                                  display_count: *mut libc::uint32_t) -> CGError;
    pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect;
    pub fn CGDisplayCreateImage(display: CGDirectDisplayID) -> CGImageRef;

    // mouse stuff
    pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError;
    pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError;
    pub fn CGAssociateMouseAndMouseCursorPosition(connected: bool) -> CGError;

    // Window Services Reference
    pub fn CGWindowListCopyWindowInfo(option: CGWindowListOption, relativeToWindow: CGWindowID ) -> CFArrayRef;
    pub fn CGWindowListCreateImage(screenBounds: CGRect,
                                   listOptions: CGWindowListOption,
                                   windowId: CGWindowID,
                                   imageOptions: CGWindowImageOption) -> CGImageRef;

}
<commit_msg>Auto merge of #88 - snapview:cgwindowlist, r=jdm<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![allow(non_upper_case_globals)]

extern crate core_foundation;

use libc;
pub use base::{CGError, boolean_t};
pub use geometry::{CGRect, CGPoint, CGSize};

use image::CGImageRef;

pub type CGDirectDisplayID = libc::uint32_t;
pub type CGWindowID        = libc::uint32_t;

pub const kCGNullWindowID: CGWindowID = 0 as CGWindowID;

pub type CGWindowListOption = libc::uint32_t;

pub const kCGWindowListOptionAll:              CGWindowListOption    = 0;
pub const kCGWindowListOptionOnScreenOnly:     CGWindowListOption    = 1 << 0;
pub const kCGWindowListOptionOnScreenAboveWindow: CGWindowListOption = 1 << 1;
pub const kCGWindowListOptionOnScreenBelowWindow: CGWindowListOption = 1 << 2;
pub const kCGWindowListOptionIncludingWindow:  CGWindowListOption    = 1 << 3;
pub const kCGWindowListExcludeDesktopElements: CGWindowListOption    = 1 << 4;

pub type CGWindowImageOption = libc::uint32_t;

pub const kCGWindowImageDefault: CGWindowImageOption = 0;
pub const kCGWindowImageBoundsIgnoreFraming: CGWindowImageOption = 1 << 0;
pub const kCGWindowImageShouldBeOpaque: CGWindowImageOption = 1 << 1;
pub const kCGWindowImageOnlyShadows: CGWindowImageOption = 1 << 2;
pub const kCGWindowImageBestResolution: CGWindowImageOption = 1 << 3;
pub const kCGWindowImageNominalResolution: CGWindowImageOption = 1 << 4;

pub use core_foundation::dictionary::{ CFDictionary, CFDictionaryRef, CFDictionaryGetValueIfPresent };
pub use core_foundation::array::{ CFArray, CFArrayRef };
pub use core_foundation::array::{ CFArrayGetCount, CFArrayGetValueAtIndex };
pub use core_foundation::base::{  CFIndex, CFRelease, CFTypeRef };

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    pub static CGRectNull: CGRect;
    pub static CGRectInfinite: CGRect;

    pub fn CGMainDisplayID() -> CGDirectDisplayID;
    pub fn CGDisplayIsActive(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAlwaysInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsAsleep(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsBuiltin(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInHWMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsInMirrorSet(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsMain(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsOnline(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayIsStereo(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayMirrorsDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayPrimaryDisplay(display: CGDirectDisplayID) -> CGDirectDisplayID;
    pub fn CGDisplayRotation(display: CGDirectDisplayID) -> libc::c_double;
    pub fn CGDisplayScreenSize(display: CGDirectDisplayID) -> CGSize;
    pub fn CGDisplaySerialNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUnitNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayUsesOpenGLAcceleration(display: CGDirectDisplayID) -> boolean_t;
    pub fn CGDisplayVendorNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGGetActiveDisplayList(max_displays: libc::uint32_t,
                                  active_displays: *mut CGDirectDisplayID,
                                  display_count: *mut libc::uint32_t) -> CGError;
    pub fn CGDisplayModelNumber(display: CGDirectDisplayID) -> libc::uint32_t;
    pub fn CGDisplayPixelsHigh(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayPixelsWide(display: CGDirectDisplayID) -> libc::size_t;
    pub fn CGDisplayBounds(display: CGDirectDisplayID) -> CGRect;
    pub fn CGDisplayCreateImage(display: CGDirectDisplayID) -> CGImageRef;

    // mouse stuff
    pub fn CGDisplayHideCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayShowCursor(display: CGDirectDisplayID) -> CGError;
    pub fn CGDisplayMoveCursorToPoint(display: CGDirectDisplayID, point: CGPoint) -> CGError;
    pub fn CGWarpMouseCursorPosition(point: CGPoint) -> CGError;
    pub fn CGAssociateMouseAndMouseCursorPosition(connected: bool) -> CGError;

    // Window Services Reference
    pub fn CGWindowListCopyWindowInfo(option: CGWindowListOption, relativeToWindow: CGWindowID ) -> CFArrayRef;
    pub fn CGWindowListCreateImage(screenBounds: CGRect,
                                   listOptions: CGWindowListOption,
                                   windowId: CGWindowID,
                                   imageOptions: CGWindowImageOption) -> CGImageRef;
    pub fn CGWindowListCreateImageFromArray(screenBounds: CGRect,
                                            windowArray: CFArrayRef,
                                            imageOptions: CGWindowImageOption) -> CGImageRef;
}
<|endoftext|>


<commit_before>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};

pub fn encode(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(&msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args = msg.args.as_ref().unwrap();
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode_arg(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(&type_tags.iter()
                                             .cloned()
                                             .collect::<String>()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    let mut bundle_bytes: Vec<u8> = Vec::new();
    bundle_bytes.extend(encode_string(&"#bundle".to_string())
                            .iter()
                            .cloned());

    match try!(encode_arg(&bundle.timetag)) {
        (Some(x), _) => {
            bundle_bytes.extend(x.iter().cloned());
        }
        (None, _) => {
            return Err(OscError::BadBundle("Missing time tag!".to_string()));
        }
    }

    if bundle.content.len() == 0 {
        // TODO: A bundle of length zero, should this really be supported?
        bundle_bytes.extend([0u8; 4].iter().cloned());
        return Ok(bundle_bytes);
    }

    for packet in &bundle.content {
        match *packet {
            OscPacket::Message(ref m) => {
                let msg = try!(encode_message(m));
                let mut msg_size = vec![0u8; 4];
                BigEndian::write_u32(&mut msg_size, msg.len() as u32);
                bundle_bytes.extend(msg_size.iter().chain(msg.iter()).cloned());
            }
            OscPacket::Bundle(ref b) => {
                let bdl = try!(encode_bundle(b));
                let mut bdl_size = vec![0u8; 4];
                BigEndian::write_u32(&mut bdl_size, bdl.len() as u32);
                bundle_bytes.extend(bdl_size.iter().chain(bdl.iter()).cloned());
            }
        }
    }

    Ok(bundle_bytes)
}

fn encode_arg(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
    match *arg {
        OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), 'i'))
        }
        OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), 'h'))
        }
        OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), 'f'))
        }
        OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), 'd'))
        }
        OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), 'c'))
        }
        OscType::String(ref x) => {
            Ok((Some(encode_string(&x)), 's'))
        }
        OscType::Blob(ref x) => {
            // let mut bytes = x.clone();
            let padded_blob_length: usize = utils::pad(x.len() as u64) as usize;
            let mut bytes = vec![0u8; 4 + padded_blob_length];
            // write length
            BigEndian::write_i32(&mut bytes[..4], x.len() as i32);
            for (i, v) in x.iter().enumerate() {
                bytes[i + 4] = *v;
            }
            Ok((Some(bytes), 'b'))
        }
        OscType::Time(ref x, ref y) => {
            Ok((Some(encode_time_tag(*x, *y)), 't'))
        }
        OscType::Midi(ref x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        OscType::Color(ref x) => {
            Ok((Some(vec![x.red, x.green, x.blue, x.alpha]), 'r'))
        }
        OscType::Bool(ref x) => {
            if *x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        OscType::Nil => {
            Ok((None, 'N'))
        }
        OscType::Inf => {
            Ok((None, 'I'))
        }
    }
}

fn encode_string(s: &String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes().into();
    bytes.push(0u8);
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[..4], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<commit_msg>Replace `.is_some()` with `if let`<commit_after>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};

pub fn encode(packet: &OscPacket) -> Result<Vec<u8>> {
    match *packet {
        OscPacket::Message(ref msg) => encode_message(msg),
        OscPacket::Bundle(ref bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: &OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(&msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if let Some(ref args) = msg.args {
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode_arg(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(&type_tags.iter()
                                             .cloned()
                                             .collect::<String>()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: &OscBundle) -> Result<Vec<u8>> {
    let mut bundle_bytes: Vec<u8> = Vec::new();
    bundle_bytes.extend(encode_string(&"#bundle".to_string())
                            .iter()
                            .cloned());

    match try!(encode_arg(&bundle.timetag)) {
        (Some(x), _) => {
            bundle_bytes.extend(x.iter().cloned());
        }
        (None, _) => {
            return Err(OscError::BadBundle("Missing time tag!".to_string()));
        }
    }

    if bundle.content.len() == 0 {
        // TODO: A bundle of length zero, should this really be supported?
        bundle_bytes.extend([0u8; 4].iter().cloned());
        return Ok(bundle_bytes);
    }

    for packet in &bundle.content {
        match *packet {
            OscPacket::Message(ref m) => {
                let msg = try!(encode_message(m));
                let mut msg_size = vec![0u8; 4];
                BigEndian::write_u32(&mut msg_size, msg.len() as u32);
                bundle_bytes.extend(msg_size.iter().chain(msg.iter()).cloned());
            }
            OscPacket::Bundle(ref b) => {
                let bdl = try!(encode_bundle(b));
                let mut bdl_size = vec![0u8; 4];
                BigEndian::write_u32(&mut bdl_size, bdl.len() as u32);
                bundle_bytes.extend(bdl_size.iter().chain(bdl.iter()).cloned());
            }
        }
    }

    Ok(bundle_bytes)
}

fn encode_arg(arg: &OscType) -> Result<(Option<Vec<u8>>, char)> {
    match *arg {
        OscType::Int(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_i32(&mut bytes, *x);
            Ok((Some(bytes), 'i'))
        }
        OscType::Long(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_i64(&mut bytes, *x);
            Ok((Some(bytes), 'h'))
        }
        OscType::Float(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_f32(&mut bytes, *x);
            Ok((Some(bytes), 'f'))
        }
        OscType::Double(ref x) => {
            let mut bytes = vec![0u8; 8];
            BigEndian::write_f64(&mut bytes, *x);
            Ok((Some(bytes), 'd'))
        }
        OscType::Char(ref x) => {
            let mut bytes = vec![0u8; 4];
            BigEndian::write_u32(&mut bytes, *x as u32);
            Ok((Some(bytes), 'c'))
        }
        OscType::String(ref x) => {
            Ok((Some(encode_string(&x)), 's'))
        }
        OscType::Blob(ref x) => {
            // let mut bytes = x.clone();
            let padded_blob_length: usize = utils::pad(x.len() as u64) as usize;
            let mut bytes = vec![0u8; 4 + padded_blob_length];
            // write length
            BigEndian::write_i32(&mut bytes[..4], x.len() as i32);
            for (i, v) in x.iter().enumerate() {
                bytes[i + 4] = *v;
            }
            Ok((Some(bytes), 'b'))
        }
        OscType::Time(ref x, ref y) => {
            Ok((Some(encode_time_tag(*x, *y)), 't'))
        }
        OscType::Midi(ref x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        OscType::Color(ref x) => {
            Ok((Some(vec![x.red, x.green, x.blue, x.alpha]), 'r'))
        }
        OscType::Bool(ref x) => {
            if *x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        OscType::Nil => {
            Ok((None, 'N'))
        }
        OscType::Inf => {
            Ok((None, 'I'))
        }
    }
}

fn encode_string(s: &String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes().into();
    bytes.push(0u8);
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = vec![0u8; 8];
    BigEndian::write_u32(&mut bytes[..4], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<|endoftext|>