<commit_before>use rustc::hir::Mutability;
use rustc::mir::{self, ValidationOp};
use rustc::ty::{self, Ty};
use rustc::middle::region::CodeExtent;

use error::{EvalError, EvalResult};
use eval_context::{EvalContext};
use memory::AccessKind;
use value::Value;
use lvalue::{Lvalue, LvalueExtra};

// Validity checks
#[derive(Copy, Clone, Debug)]
pub struct ValidationCtx {
    op: ValidationOp,
    region: Option<CodeExtent>,
    mutbl: Mutability,
}

impl ValidationCtx {
    pub fn new(op: ValidationOp) -> Self {
        ValidationCtx {
            op, region: None, mutbl: Mutability::MutMutable,
        }
    }
}

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    fn validate_variant(
        &mut self,
        lvalue: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        variant: &ty::VariantDef,
        subst: &ty::subst::Substs<'tcx>,
        vctx: ValidationCtx,
    ) -> EvalResult<'tcx> {
        // TODO: Take visibility/privacy into account.
        for (idx, field) in variant.fields.iter().enumerate() {
            let field_ty = field.ty(self.tcx, subst);
            let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
            self.validate(field_lvalue, field_ty, vctx)?;
        }
        Ok(())
    }

    fn validate_ptr(&mut self, val: Value, pointee_ty: Ty<'tcx>, vctx: ValidationCtx) -> EvalResult<'tcx> {
        // Check alignment and non-NULLness
        let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?;
        let ptr = val.into_ptr(&mut self.memory)?;
        self.memory.check_align(ptr, align)?;

        // Recurse
        let pointee_lvalue = self.val_to_lvalue(val, pointee_ty)?;
        self.validate(pointee_lvalue, pointee_ty, vctx)
    }

    /// Validate the lvalue at the given type. If `release` is true, just do a release of all write locks
    pub(super) fn validate(&mut self, lvalue: Lvalue<'tcx>, ty: Ty<'tcx>, mut vctx: ValidationCtx) -> EvalResult<'tcx>
    {
        use rustc::ty::TypeVariants::*;
        use rustc::ty::RegionKind::*;
        use rustc::ty::AdtKind;
        use self::Mutability::*;
        trace!("Validating {:?} at type {}, context {:?}", lvalue, ty, vctx);

        // Decide whether this type *owns* the memory it covers (like integers), or whether it
        // just assembles pieces (that each own their memory) together to a larger whole.
        // TODO: Currently, we don't acquire locks for padding and discriminants. We should.
        let is_owning = match ty.sty {
            TyInt(_) | TyUint(_) | TyRawPtr(_) |
            TyBool | TyFloat(_) | TyChar | TyStr |
            TyRef(..) | TyFnPtr(..) | TyNever => true,
            TyAdt(adt, _) if adt.is_box() => true,
            TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) => false,
            TyParam(_) | TyInfer(_) => bug!("I got an incomplete type for validation"),
            _ => return Err(EvalError::Unimplemented(format!("Unimplemented type encountered when checking validity."))),
        };
        if is_owning {
            match lvalue {
                Lvalue::Ptr { ptr, extra, aligned: _ } => {
                    // Determine the size
                    // FIXME: Can we reuse size_and_align_of_dst for Lvalues?
                    let len = match self.type_size(ty)? {
                        Some(size) => {
                            assert_eq!(extra, LvalueExtra::None, "Got a fat ptr to a sized type");
                            size
                        }
                        None => {
                            // The only unsized typ we concider "owning" is TyStr.
                            assert_eq!(ty.sty, TyStr, "Found a surprising unsized owning type");
                            // The extra must be the length, in bytes.
                            match extra {
                                LvalueExtra::Length(len) => len,
                                _ => bug!("TyStr must have a length as extra"),
                            }
                        }
                    };
                    // Handle locking
                    if len > 0 {
                        let ptr = ptr.to_ptr()?;
                        let access = match vctx.mutbl { MutMutable => AccessKind::Write, MutImmutable => AccessKind::Read };
                        match vctx.op {
                            ValidationOp::Acquire => self.memory.acquire_lock(ptr, len, vctx.region, access)?,
                            ValidationOp::Release => self.memory.release_write_lock_until(ptr, len, None)?,
                            ValidationOp::Suspend(region) => self.memory.release_write_lock_until(ptr, len, Some(region))?,
                        }
                    }
                }
                Lvalue::Local { .. } | Lvalue::Global(..) => {
                    // These are not backed by memory, so we have nothing to do.
                }
            }
        }

        match ty.sty {
            TyInt(_) | TyUint(_) | TyRawPtr(_) => {
                // TODO: Make sure these are not undef.
                // We could do a bounds-check and other sanity checks on the lvalue, but it would be a bug in miri for this to ever fail.
                Ok(())
            }
            TyBool | TyFloat(_) | TyChar | TyStr => {
                // TODO: Check if these are valid bool/float/codepoint/UTF-8, respectively (and in particular, not undef).
                Ok(())
            }
            TyNever => {
                Err(EvalError::ValidationFailure(format!("The empty type is never valid.")))
            }
            TyRef(region, ty::TypeAndMut { ty: pointee_ty, mutbl }) => {
                let val = self.read_lvalue(lvalue)?;
                // Sharing restricts our context
                if mutbl == MutImmutable {
                    // Actually, in case of releasing-validation, this means we are done.
                    if vctx.op != ValidationOp::Acquire {
                        return Ok(());
                    }
                    vctx.mutbl = MutImmutable;
                }
                // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet,
                // we record the region of this borrow to the context.
                if vctx.region == None {
                    match *region {
                        ReScope(ce) => vctx.region = Some(ce),
                        // It is possible for us to encode erased lifetimes here because the lifetimes in
                        // this functions' Subst will be erased.
                        _ => {},
                    }
                }
                self.validate_ptr(val, pointee_ty, vctx)
            }
            TyAdt(adt, _) if adt.is_box() => {
                let val = self.read_lvalue(lvalue)?;
                self.validate_ptr(val, ty.boxed_ty(), vctx)
            }
            TyFnPtr(_sig) => {
                // TODO: The function names here could need some improvement.
                let ptr = self.read_lvalue(lvalue)?.into_ptr(&mut self.memory)?.to_ptr()?;
                self.memory.get_fn(ptr)?;
                // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
                Ok(())
            }

            // Compound types
            TySlice(elem_ty) => {
                let len = match lvalue {
                    Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => len,
                    _ => bug!("acquire_valid of a TySlice given non-slice lvalue: {:?}", lvalue),
                };
                for i in 0..len {
                    let inner_lvalue = self.lvalue_index(lvalue, ty, i)?;
                    self.validate(inner_lvalue, elem_ty, vctx)?;
                }
                Ok(())
            }
            TyArray(elem_ty, len) => {
                for i in 0..len {
                    let inner_lvalue = self.lvalue_index(lvalue, ty, i as u64)?;
                    self.validate(inner_lvalue, elem_ty, vctx)?;
                }
                Ok(())
            }
            TyAdt(adt, subst) => {
                if Some(adt.did) == self.tcx.lang_items.unsafe_cell_type() {
                    // No locks for unsafe cells.  Also no other validation, the only field is private anyway.
                    return Ok(());
                }

                match adt.adt_kind() {
                    AdtKind::Enum => {
                        // TODO: Can we get the discriminant without forcing an allocation?
                        let ptr = self.force_allocation(lvalue)?.to_ptr()?;
                        let discr = self.read_discriminant_value(ptr, ty)?;

                        // Get variant index for discriminant
                        let variant_idx = adt.discriminants(self.tcx)
                            .position(|variant_discr| variant_discr.to_u128_unchecked() == discr)
                            .ok_or(EvalError::InvalidDiscriminant)?;
                        let variant = &adt.variants[variant_idx];

                        if variant.fields.len() > 0 {
                            // Downcast to this variant, if needed
                            let lvalue = if adt.variants.len() > 1 {
                                self.eval_lvalue_projection(lvalue, ty, &mir::ProjectionElem::Downcast(adt, variant_idx))?
                            } else {
                                lvalue
                            };

                            // Recursively validate the fields
                            self.validate_variant(lvalue, ty, variant, subst, vctx)
                        } else {
                            // No fields, nothing left to check.  Downcasting may fail, e.g. in case of a CEnum.
                            Ok(())
                        }
                    }
                    AdtKind::Struct => {
                        self.validate_variant(lvalue, ty, adt.struct_variant(), subst, vctx)
                    }
                    AdtKind::Union => {
                        // No guarantees are provided for union types.
                        // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?)
                        Ok(())
                    }
                }
            }
            TyTuple(ref types, _) => {
                for (idx, field_ty) in types.iter().enumerate() {
                    let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
                    self.validate(field_lvalue, field_ty, vctx)?;
                }
                Ok(())
            }
            TyClosure(def_id, ref closure_substs) => {
                for (idx, field_ty) in closure_substs.upvar_tys(def_id, self.tcx).enumerate() {
                    let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
                    self.validate(field_lvalue, field_ty, vctx)?;
                }
                // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
                // Is there other things we can/should check?  Like vtable pointers?
                Ok(())
            }
            _ => bug!("We already establishd that this is a type we support.")
        }
    }
}
<commit_msg>Handle trait objects.  Only very superficial checking of the vtable for now. (88)<commit_after>use rustc::hir::Mutability;
use rustc::mir::{self, ValidationOp};
use rustc::ty::{self, Ty};
use rustc::middle::region::CodeExtent;

use error::{EvalError, EvalResult};
use eval_context::{EvalContext};
use memory::AccessKind;
use value::Value;
use lvalue::{Lvalue, LvalueExtra};

// Validity checks
#[derive(Copy, Clone, Debug)]
pub struct ValidationCtx {
    op: ValidationOp,
    region: Option<CodeExtent>,
    mutbl: Mutability,
}

impl ValidationCtx {
    pub fn new(op: ValidationOp) -> Self {
        ValidationCtx {
            op, region: None, mutbl: Mutability::MutMutable,
        }
    }
}

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    fn validate_variant(
        &mut self,
        lvalue: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        variant: &ty::VariantDef,
        subst: &ty::subst::Substs<'tcx>,
        vctx: ValidationCtx,
    ) -> EvalResult<'tcx> {
        // TODO: Take visibility/privacy into account.
        for (idx, field) in variant.fields.iter().enumerate() {
            let field_ty = field.ty(self.tcx, subst);
            let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
            self.validate(field_lvalue, field_ty, vctx)?;
        }
        Ok(())
    }

    fn validate_ptr(&mut self, val: Value, pointee_ty: Ty<'tcx>, vctx: ValidationCtx) -> EvalResult<'tcx> {
        // Check alignment and non-NULLness
        let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?;
        let ptr = val.into_ptr(&mut self.memory)?;
        self.memory.check_align(ptr, align)?;

        // Recurse
        let pointee_lvalue = self.val_to_lvalue(val, pointee_ty)?;
        self.validate(pointee_lvalue, pointee_ty, vctx)
    }

    /// Validate the lvalue at the given type. If `release` is true, just do a release of all write locks
    pub(super) fn validate(&mut self, lvalue: Lvalue<'tcx>, ty: Ty<'tcx>, mut vctx: ValidationCtx) -> EvalResult<'tcx>
    {
        use rustc::ty::TypeVariants::*;
        use rustc::ty::RegionKind::*;
        use rustc::ty::AdtKind;
        use self::Mutability::*;
        trace!("Validating {:?} at type {}, context {:?}", lvalue, ty, vctx);

        // Decide whether this type *owns* the memory it covers (like integers), or whether it
        // just assembles pieces (that each own their memory) together to a larger whole.
        // TODO: Currently, we don't acquire locks for padding and discriminants. We should.
        let is_owning = match ty.sty {
            TyInt(_) | TyUint(_) | TyRawPtr(_) |
            TyBool | TyFloat(_) | TyChar | TyStr |
            TyRef(..) | TyFnPtr(..) | TyNever => true,
            TyAdt(adt, _) if adt.is_box() => true,
            TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | TyDynamic(..) => false,
            TyParam(_) | TyInfer(_) => bug!("I got an incomplete type for validation"),
            _ => return Err(EvalError::Unimplemented(format!("Unimplemented type encountered when checking validity."))),
        };
        if is_owning {
            match lvalue {
                Lvalue::Ptr { ptr, extra, aligned: _ } => {
                    // Determine the size
                    // FIXME: Can we reuse size_and_align_of_dst for Lvalues?
                    let len = match self.type_size(ty)? {
                        Some(size) => {
                            assert_eq!(extra, LvalueExtra::None, "Got a fat ptr to a sized type");
                            size
                        }
                        None => {
                            // The only unsized typ we concider "owning" is TyStr.
                            assert_eq!(ty.sty, TyStr, "Found a surprising unsized owning type");
                            // The extra must be the length, in bytes.
                            match extra {
                                LvalueExtra::Length(len) => len,
                                _ => bug!("TyStr must have a length as extra"),
                            }
                        }
                    };
                    // Handle locking
                    if len > 0 {
                        let ptr = ptr.to_ptr()?;
                        let access = match vctx.mutbl { MutMutable => AccessKind::Write, MutImmutable => AccessKind::Read };
                        match vctx.op {
                            ValidationOp::Acquire => self.memory.acquire_lock(ptr, len, vctx.region, access)?,
                            ValidationOp::Release => self.memory.release_write_lock_until(ptr, len, None)?,
                            ValidationOp::Suspend(region) => self.memory.release_write_lock_until(ptr, len, Some(region))?,
                        }
                    }
                }
                Lvalue::Local { .. } | Lvalue::Global(..) => {
                    // These are not backed by memory, so we have nothing to do.
                }
            }
        }

        match ty.sty {
            TyInt(_) | TyUint(_) | TyRawPtr(_) => {
                // TODO: Make sure these are not undef.
                // We could do a bounds-check and other sanity checks on the lvalue, but it would be a bug in miri for this to ever fail.
                Ok(())
            }
            TyBool | TyFloat(_) | TyChar | TyStr => {
                // TODO: Check if these are valid bool/float/codepoint/UTF-8, respectively (and in particular, not undef).
                Ok(())
            }
            TyNever => {
                Err(EvalError::ValidationFailure(format!("The empty type is never valid.")))
            }
            TyRef(region, ty::TypeAndMut { ty: pointee_ty, mutbl }) => {
                let val = self.read_lvalue(lvalue)?;
                // Sharing restricts our context
                if mutbl == MutImmutable {
                    // Actually, in case of releasing-validation, this means we are done.
                    if vctx.op != ValidationOp::Acquire {
                        return Ok(());
                    }
                    vctx.mutbl = MutImmutable;
                }
                // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet,
                // we record the region of this borrow to the context.
                if vctx.region == None {
                    match *region {
                        ReScope(ce) => vctx.region = Some(ce),
                        // It is possible for us to encode erased lifetimes here because the lifetimes in
                        // this functions' Subst will be erased.
                        _ => {},
                    }
                }
                self.validate_ptr(val, pointee_ty, vctx)
            }
            TyAdt(adt, _) if adt.is_box() => {
                let val = self.read_lvalue(lvalue)?;
                self.validate_ptr(val, ty.boxed_ty(), vctx)
            }
            TyFnPtr(_sig) => {
                // TODO: The function names here could need some improvement.
                let ptr = self.read_lvalue(lvalue)?.into_ptr(&mut self.memory)?.to_ptr()?;
                self.memory.get_fn(ptr)?;
                // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
                Ok(())
            }

            // Compound types
            TySlice(elem_ty) => {
                let len = match lvalue {
                    Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => len,
                    _ => bug!("acquire_valid of a TySlice given non-slice lvalue: {:?}", lvalue),
                };
                for i in 0..len {
                    let inner_lvalue = self.lvalue_index(lvalue, ty, i)?;
                    self.validate(inner_lvalue, elem_ty, vctx)?;
                }
                Ok(())
            }
            TyArray(elem_ty, len) => {
                for i in 0..len {
                    let inner_lvalue = self.lvalue_index(lvalue, ty, i as u64)?;
                    self.validate(inner_lvalue, elem_ty, vctx)?;
                }
                Ok(())
            }
            TyDynamic(_data, _region) => {
                // Check that this is a valid vtable
                let vtable = match lvalue {
                    Lvalue::Ptr { extra: LvalueExtra::Vtable(vtable), .. } => vtable,
                    _ => bug!("acquire_valid of a TyDynamic given non-trait-object lvalue: {:?}", lvalue),
                };
                self.read_size_and_align_from_vtable(vtable)?;
                // TODO: Check that the vtable contains all the function pointers we expect it to have.
                // TODO: Is there anything we can/should validate here?  Trait objects cannot have any operations performed
                // on them directly.  We cannot, in general, even acquire any locks as the trait object *could*
                // contain an UnsafeCell.  If we call functions to get access to data, we will validate
                // their return values.  So, it doesn't seem like there's anything to do.
                Ok(())
            }
            TyAdt(adt, subst) => {
                if Some(adt.did) == self.tcx.lang_items.unsafe_cell_type() {
                    // No locks for unsafe cells.  Also no other validation, the only field is private anyway.
                    return Ok(());
                }

                match adt.adt_kind() {
                    AdtKind::Enum => {
                        // TODO: Can we get the discriminant without forcing an allocation?
                        let ptr = self.force_allocation(lvalue)?.to_ptr()?;
                        let discr = self.read_discriminant_value(ptr, ty)?;

                        // Get variant index for discriminant
                        let variant_idx = adt.discriminants(self.tcx)
                            .position(|variant_discr| variant_discr.to_u128_unchecked() == discr)
                            .ok_or(EvalError::InvalidDiscriminant)?;
                        let variant = &adt.variants[variant_idx];

                        if variant.fields.len() > 0 {
                            // Downcast to this variant, if needed
                            let lvalue = if adt.variants.len() > 1 {
                                self.eval_lvalue_projection(lvalue, ty, &mir::ProjectionElem::Downcast(adt, variant_idx))?
                            } else {
                                lvalue
                            };

                            // Recursively validate the fields
                            self.validate_variant(lvalue, ty, variant, subst, vctx)
                        } else {
                            // No fields, nothing left to check.  Downcasting may fail, e.g. in case of a CEnum.
                            Ok(())
                        }
                    }
                    AdtKind::Struct => {
                        self.validate_variant(lvalue, ty, adt.struct_variant(), subst, vctx)
                    }
                    AdtKind::Union => {
                        // No guarantees are provided for union types.
                        // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?)
                        Ok(())
                    }
                }
            }
            TyTuple(ref types, _) => {
                for (idx, field_ty) in types.iter().enumerate() {
                    let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
                    self.validate(field_lvalue, field_ty, vctx)?;
                }
                Ok(())
            }
            TyClosure(def_id, ref closure_substs) => {
                for (idx, field_ty) in closure_substs.upvar_tys(def_id, self.tcx).enumerate() {
                    let field_lvalue = self.lvalue_field(lvalue, idx, ty, field_ty)?;
                    self.validate(field_lvalue, field_ty, vctx)?;
                }
                // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
                // Is there other things we can/should check?  Like vtable pointers?
                Ok(())
            }
            _ => bug!("We already establishd that this is a type we support.")
        }
    }
}
<|endoftext|>


<commit_before>#[doc = "Rust wrappers around the raw JS apis"];

use bg = jsapi::bindgen;
use libc::types::os::arch::c95::{size_t, c_uint};
use std::map::{hashmap, str_hash};

export rt;
export cx;
export jsobj;
export methods;
export compartment;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

type rt = @rt_rsrc;

struct rt_rsrc {
    ptr : *JSRuntime,
    drop {
        JS_Finish(self.ptr);
    }
}

fn new_runtime(p : {ptr: *JSRuntime}) -> rt {
    return @rt_rsrc {
        ptr: p.ptr
    }
}

impl rt {
    fn cx() -> cx {
        new_context({ ptr: JS_NewContext(self.ptr, default_stacksize as size_t),
                      rt: self})
    }
}

fn rt() -> rt {
    return new_runtime({ptr: JS_Init(default_heapsize)})
}

// ___________________________________________________________________________
// contexts

type cx = @cx_rsrc;

struct cx_rsrc {
    ptr : *JSContext,
    rt: rt,
    classes: hashmap<~str, @JSClass>,

    drop {
        JS_DestroyContext(self.ptr);
    }
}

fn new_context(rec : {ptr: *JSContext, rt: rt}) -> cx {
    return @cx_rsrc {
        ptr: rec.ptr,
        rt: rec.rt,
        classes: str_hash()
    }
}

impl cx {
    fn rooted_obj(obj: *JSObject) -> jsobj {
        let jsobj = @jsobj_rsrc {cx: self, cxptr: self.ptr, ptr: obj};
        JS_AddObjectRoot(self.ptr, ptr::addr_of(jsobj.ptr));
        jsobj
    }

    fn set_default_options_and_version() {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT);
        self.set_version(JSVERSION_LATEST);
    }

    fn set_options(v: c_uint) {
        JS_SetOptions(self.ptr, v);
    }

    fn set_version(v: i32) {
        JS_SetVersion(self.ptr, v);
    }

    fn set_logging_error_reporter() {
        JS_SetErrorReporter(self.ptr, reportError);
    }

    fn set_error_reporter(reportfn: *u8) {
        JS_SetErrorReporter(self.ptr, reportfn);
    }

    fn new_compartment(globclsfn: fn(name_pool) -> JSClass) -> Result<compartment,()> {
        let np = name_pool();
        let globcls = @globclsfn(np);
        let globobj = JS_NewGlobalObject(self.ptr, ptr::to_unsafe_ptr(&*globcls), null());
        result(JS_InitStandardClasses(self.ptr, globobj)).chain(|_ok| {
            let compartment = @{cx: self,
                                name_pool: np,
                                mut global_funcs: ~[],
                                mut global_props: ~[],
                                global_class: globcls,
                                global_obj: self.rooted_obj(globobj),
                                global_protos: str_hash()
                               };
            self.set_cx_private(ptr::to_unsafe_ptr(&*compartment) as *());
            Ok(compartment)
        })
    }

    fn evaluate_script(glob: jsobj, bytes: ~[u8], filename: ~str, line_num: uint)
                    -> Result<(),()> {
        vec::as_buf(bytes, |bytes_ptr, bytes_len| {
            str::as_c_str(filename, |filename_cstr| {
                let bytes_ptr = bytes_ptr as *c_char;
                let rval: jsval = JSVAL_NULL;
                #debug["Evaluating script from %s with bytes %?", filename, bytes];
                if JS_EvaluateScript(self.ptr, glob.ptr,
                                     bytes_ptr, bytes_len as c_uint,
                                     filename_cstr, line_num as c_uint,
                                     ptr::addr_of(rval)) == ERR {
                    #debug["...err!"];
                    Err(())
                } else {
                    // we could return the script result but then we'd have
                    // to root it and so forth and, really, who cares?
                    #debug["...ok!"];
                    Ok(())
                }
            })
        })
    }

    fn lookup_class_name(s: ~str) ->  @JSClass {
      option::expect(self.classes.find(s),
           #fmt("Class %s not found in class table", s))
    }

    unsafe fn get_cx_private() -> *() {
        unsafe::reinterpret_cast(&JS_GetContextPrivate(self.ptr))
    }

    unsafe fn set_cx_private(data: *()) {
        JS_SetContextPrivate(self.ptr, unsafe::reinterpret_cast(&data));
    }

    unsafe fn get_obj_private(obj: *JSObject) -> *() {
        unsafe::reinterpret_cast(&JS_GetPrivate(obj))
    }

    unsafe fn set_obj_private(obj: *JSObject, data: *()) {
        JS_SetPrivate(obj, unsafe::reinterpret_cast(&data));
    }
}

extern fn reportError(_cx: *JSContext,
                     msg: *c_char,
                     report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {~"none"};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        #error["Error at %s:%?: %s\n", fname, lineno, msg];
    }
}

// ___________________________________________________________________________
// compartment

type bare_compartment = {
    cx: cx,
    name_pool: name_pool,
    mut global_funcs: ~[@~[JSFunctionSpec]],
    mut global_props: ~[@~[JSPropertySpec]],
    global_class: @JSClass,
    global_obj: jsobj,
    global_protos: hashmap<~str, jsobj>
};

trait methods {
    fn define_functions(specfn: fn(name_pool) -> ~[JSFunctionSpec]) -> Result<(),()>;
    fn define_properties(specfn: fn() -> ~[JSPropertySpec]) -> Result<(),()>;
    fn define_property(name: ~str, value: jsval, getter: JSPropertyOp,
                       setter: JSStrictPropertyOp, attrs: c_uint) -> Result<(),()>;
    fn new_object(class_name: ~str, proto: *JSObject, parent: *JSObject) -> Result<jsobj, ()>;
    fn new_object_with_proto(class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()>;
    fn register_class(class_fn: fn(bare_compartment) -> JSClass);
    fn get_global_proto(name: ~str) -> jsobj;
    fn stash_global_proto(name: ~str, proto: jsobj);
    fn add_name(name: ~str) -> *c_char;
}

type compartment = @bare_compartment;

impl bare_compartment : methods {
    fn define_functions(specfn: fn(name_pool) -> ~[JSFunctionSpec]) -> Result<(),()> {
        let specvec = @specfn(self.name_pool);
        vec::push(self.global_funcs, specvec);
        vec::as_buf(*specvec, |specs, _len| {
            result(JS_DefineFunctions(self.cx.ptr, self.global_obj.ptr, specs))
        })
    }
    fn define_properties(specfn: fn() -> ~[JSPropertySpec]) -> Result<(),()> {
        let specvec = @specfn();
        vec::push(self.global_props, specvec);
        vec::as_buf(*specvec, |specs, _len| {
            result(JS_DefineProperties(self.cx.ptr, self.global_obj.ptr, specs))
        })
    }
    fn define_property(name: ~str, value: jsval, getter: JSPropertyOp, setter: JSStrictPropertyOp,
                       attrs: c_uint)
                    -> Result<(),()> {
        result(JS_DefineProperty(self.cx.ptr, self.global_obj.ptr, self.add_name(name),
                                 value, getter, setter, attrs))
    }
    fn new_object(class_name: ~str, proto: *JSObject, parent: *JSObject)
               -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                  proto, parent));
        result_obj(obj)
    }
    fn new_object_with_proto(class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let proto = option::expect(self.global_protos.find(proto_name),
           #fmt("new_object_with_proto: expected to find %s in the proto \
              table", proto_name));
        let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                  proto.ptr, parent));
        result_obj(obj)
    }
    fn get_global_proto(name: ~str) -> jsobj {
        self.global_protos.get(name)
    }
    fn stash_global_proto(name: ~str, proto: jsobj) {
        if !self.global_protos.insert(name, proto) {
            fail ~"Duplicate global prototype registered; you're gonna have a bad time."
        }
    }
    fn register_class(class_fn: fn(bare_compartment) -> JSClass) {
        let classptr = @class_fn(self);
        if !self.cx.classes.insert(
            unsafe { str::unsafe::from_c_str(classptr.name) },
            classptr) {
            fail ~"Duplicate JSClass registered; you're gonna have a bad time."
        }
    }
    fn add_name(name: ~str) -> *c_char {
        self.name_pool.add(copy name)
    }
}

// ___________________________________________________________________________
// objects

type jsobj = @jsobj_rsrc;

struct jsobj_rsrc {
    cx : cx,
    cxptr : *JSContext,
    ptr : *JSObject,
    drop {
        JS_RemoveObjectRoot(self.cxptr, ptr::addr_of(self.ptr));
    }
}

impl jsobj_rsrc {
    fn new_object(rec : {cx: cx, cxptr: *JSContext, ptr: *JSObject}) -> jsobj {
        return @jsobj_rsrc {
            cx: rec.cx,
            cxptr: rec.cxptr,
            ptr: rec.ptr
        }
    }
}

// ___________________________________________________________________________
// random utilities

trait to_jsstr {
    fn to_jsstr(cx: cx) -> *JSString;
}

impl ~str : to_jsstr {
    fn to_jsstr(cx: cx) -> *JSString {
        str::as_buf(self, |buf, len| {
            let cbuf = unsafe { unsafe::reinterpret_cast(&buf) };
            bg::JS_NewStringCopyN(cx.ptr, cbuf, len as size_t)
        })
    }
}

#[cfg(test)]
mod test {

    #[test]
    fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.set_default_options_and_version();
        cx.set_logging_error_reporter();
        cx.new_compartment(global::global_class).chain(|comp| {
            comp.define_functions(global::debug_fns);

            let bytes = str::to_bytes(~"debug(22);");
            cx.evaluate_script(comp.global_obj, bytes, ~"test", 1u)
        });
    }

}
<commit_msg>Fix build break from hashmap->HashMap<commit_after>#[doc = "Rust wrappers around the raw JS apis"];

use bg = jsapi::bindgen;
use libc::types::os::arch::c95::{size_t, c_uint};
use std::map::{HashMap, str_hash};

export rt;
export cx;
export jsobj;
export methods;
export compartment;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

type rt = @rt_rsrc;

struct rt_rsrc {
    ptr : *JSRuntime,
    drop {
        JS_Finish(self.ptr);
    }
}

fn new_runtime(p : {ptr: *JSRuntime}) -> rt {
    return @rt_rsrc {
        ptr: p.ptr
    }
}

impl rt {
    fn cx() -> cx {
        new_context({ ptr: JS_NewContext(self.ptr, default_stacksize as size_t),
                      rt: self})
    }
}

fn rt() -> rt {
    return new_runtime({ptr: JS_Init(default_heapsize)})
}

// ___________________________________________________________________________
// contexts

type cx = @cx_rsrc;

struct cx_rsrc {
    ptr : *JSContext,
    rt: rt,
    classes: HashMap<~str, @JSClass>,

    drop {
        JS_DestroyContext(self.ptr);
    }
}

fn new_context(rec : {ptr: *JSContext, rt: rt}) -> cx {
    return @cx_rsrc {
        ptr: rec.ptr,
        rt: rec.rt,
        classes: str_hash()
    }
}

impl cx {
    fn rooted_obj(obj: *JSObject) -> jsobj {
        let jsobj = @jsobj_rsrc {cx: self, cxptr: self.ptr, ptr: obj};
        JS_AddObjectRoot(self.ptr, ptr::addr_of(jsobj.ptr));
        jsobj
    }

    fn set_default_options_and_version() {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT);
        self.set_version(JSVERSION_LATEST);
    }

    fn set_options(v: c_uint) {
        JS_SetOptions(self.ptr, v);
    }

    fn set_version(v: i32) {
        JS_SetVersion(self.ptr, v);
    }

    fn set_logging_error_reporter() {
        JS_SetErrorReporter(self.ptr, reportError);
    }

    fn set_error_reporter(reportfn: *u8) {
        JS_SetErrorReporter(self.ptr, reportfn);
    }

    fn new_compartment(globclsfn: fn(name_pool) -> JSClass) -> Result<compartment,()> {
        let np = name_pool();
        let globcls = @globclsfn(np);
        let globobj = JS_NewGlobalObject(self.ptr, ptr::to_unsafe_ptr(&*globcls), null());
        result(JS_InitStandardClasses(self.ptr, globobj)).chain(|_ok| {
            let compartment = @{cx: self,
                                name_pool: np,
                                mut global_funcs: ~[],
                                mut global_props: ~[],
                                global_class: globcls,
                                global_obj: self.rooted_obj(globobj),
                                global_protos: str_hash()
                               };
            self.set_cx_private(ptr::to_unsafe_ptr(&*compartment) as *());
            Ok(compartment)
        })
    }

    fn evaluate_script(glob: jsobj, bytes: ~[u8], filename: ~str, line_num: uint)
                    -> Result<(),()> {
        vec::as_buf(bytes, |bytes_ptr, bytes_len| {
            str::as_c_str(filename, |filename_cstr| {
                let bytes_ptr = bytes_ptr as *c_char;
                let rval: jsval = JSVAL_NULL;
                #debug["Evaluating script from %s with bytes %?", filename, bytes];
                if JS_EvaluateScript(self.ptr, glob.ptr,
                                     bytes_ptr, bytes_len as c_uint,
                                     filename_cstr, line_num as c_uint,
                                     ptr::addr_of(rval)) == ERR {
                    #debug["...err!"];
                    Err(())
                } else {
                    // we could return the script result but then we'd have
                    // to root it and so forth and, really, who cares?
                    #debug["...ok!"];
                    Ok(())
                }
            })
        })
    }

    fn lookup_class_name(s: ~str) ->  @JSClass {
      option::expect(self.classes.find(s),
           #fmt("Class %s not found in class table", s))
    }

    unsafe fn get_cx_private() -> *() {
        unsafe::reinterpret_cast(&JS_GetContextPrivate(self.ptr))
    }

    unsafe fn set_cx_private(data: *()) {
        JS_SetContextPrivate(self.ptr, unsafe::reinterpret_cast(&data));
    }

    unsafe fn get_obj_private(obj: *JSObject) -> *() {
        unsafe::reinterpret_cast(&JS_GetPrivate(obj))
    }

    unsafe fn set_obj_private(obj: *JSObject, data: *()) {
        JS_SetPrivate(obj, unsafe::reinterpret_cast(&data));
    }
}

extern fn reportError(_cx: *JSContext,
                     msg: *c_char,
                     report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {~"none"};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        #error["Error at %s:%?: %s\n", fname, lineno, msg];
    }
}

// ___________________________________________________________________________
// compartment

type bare_compartment = {
    cx: cx,
    name_pool: name_pool,
    mut global_funcs: ~[@~[JSFunctionSpec]],
    mut global_props: ~[@~[JSPropertySpec]],
    global_class: @JSClass,
    global_obj: jsobj,
    global_protos: HashMap<~str, jsobj>
};

trait methods {
    fn define_functions(specfn: fn(name_pool) -> ~[JSFunctionSpec]) -> Result<(),()>;
    fn define_properties(specfn: fn() -> ~[JSPropertySpec]) -> Result<(),()>;
    fn define_property(name: ~str, value: jsval, getter: JSPropertyOp,
                       setter: JSStrictPropertyOp, attrs: c_uint) -> Result<(),()>;
    fn new_object(class_name: ~str, proto: *JSObject, parent: *JSObject) -> Result<jsobj, ()>;
    fn new_object_with_proto(class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()>;
    fn register_class(class_fn: fn(bare_compartment) -> JSClass);
    fn get_global_proto(name: ~str) -> jsobj;
    fn stash_global_proto(name: ~str, proto: jsobj);
    fn add_name(name: ~str) -> *c_char;
}

type compartment = @bare_compartment;

impl bare_compartment : methods {
    fn define_functions(specfn: fn(name_pool) -> ~[JSFunctionSpec]) -> Result<(),()> {
        let specvec = @specfn(self.name_pool);
        vec::push(self.global_funcs, specvec);
        vec::as_buf(*specvec, |specs, _len| {
            result(JS_DefineFunctions(self.cx.ptr, self.global_obj.ptr, specs))
        })
    }
    fn define_properties(specfn: fn() -> ~[JSPropertySpec]) -> Result<(),()> {
        let specvec = @specfn();
        vec::push(self.global_props, specvec);
        vec::as_buf(*specvec, |specs, _len| {
            result(JS_DefineProperties(self.cx.ptr, self.global_obj.ptr, specs))
        })
    }
    fn define_property(name: ~str, value: jsval, getter: JSPropertyOp, setter: JSStrictPropertyOp,
                       attrs: c_uint)
                    -> Result<(),()> {
        result(JS_DefineProperty(self.cx.ptr, self.global_obj.ptr, self.add_name(name),
                                 value, getter, setter, attrs))
    }
    fn new_object(class_name: ~str, proto: *JSObject, parent: *JSObject)
               -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                  proto, parent));
        result_obj(obj)
    }
    fn new_object_with_proto(class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let proto = option::expect(self.global_protos.find(proto_name),
           #fmt("new_object_with_proto: expected to find %s in the proto \
              table", proto_name));
        let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                  proto.ptr, parent));
        result_obj(obj)
    }
    fn get_global_proto(name: ~str) -> jsobj {
        self.global_protos.get(name)
    }
    fn stash_global_proto(name: ~str, proto: jsobj) {
        if !self.global_protos.insert(name, proto) {
            fail ~"Duplicate global prototype registered; you're gonna have a bad time."
        }
    }
    fn register_class(class_fn: fn(bare_compartment) -> JSClass) {
        let classptr = @class_fn(self);
        if !self.cx.classes.insert(
            unsafe { str::unsafe::from_c_str(classptr.name) },
            classptr) {
            fail ~"Duplicate JSClass registered; you're gonna have a bad time."
        }
    }
    fn add_name(name: ~str) -> *c_char {
        self.name_pool.add(copy name)
    }
}

// ___________________________________________________________________________
// objects

type jsobj = @jsobj_rsrc;

struct jsobj_rsrc {
    cx : cx,
    cxptr : *JSContext,
    ptr : *JSObject,
    drop {
        JS_RemoveObjectRoot(self.cxptr, ptr::addr_of(self.ptr));
    }
}

impl jsobj_rsrc {
    fn new_object(rec : {cx: cx, cxptr: *JSContext, ptr: *JSObject}) -> jsobj {
        return @jsobj_rsrc {
            cx: rec.cx,
            cxptr: rec.cxptr,
            ptr: rec.ptr
        }
    }
}

// ___________________________________________________________________________
// random utilities

trait to_jsstr {
    fn to_jsstr(cx: cx) -> *JSString;
}

impl ~str : to_jsstr {
    fn to_jsstr(cx: cx) -> *JSString {
        str::as_buf(self, |buf, len| {
            let cbuf = unsafe { unsafe::reinterpret_cast(&buf) };
            bg::JS_NewStringCopyN(cx.ptr, cbuf, len as size_t)
        })
    }
}

#[cfg(test)]
mod test {

    #[test]
    fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.set_default_options_and_version();
        cx.set_logging_error_reporter();
        cx.new_compartment(global::global_class).chain(|comp| {
            comp.define_functions(global::debug_fns);

            let bytes = str::to_bytes(~"debug(22);");
            cx.evaluate_script(comp.global_obj, bytes, ~"test", 1u)
        });
    }

}
<|endoftext|>


<commit_before>pub mod map;
mod navigate;
mod node;
mod search;
pub mod set;

#[doc(hidden)]
trait Recover<Q: ?Sized> {
    type Key;

    fn get(&self, key: &Q) -> Option<&Self::Key>;
    fn take(&mut self, key: &Q) -> Option<Self::Key>;
    fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
}

#[inline(always)]
pub unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T {
    val.unwrap_or_else(|| {
        if cfg!(debug_assertions) {
            panic!("'unchecked' unwrap on None in BTreeMap");
        } else {
            unsafe {
                core::intrinsics::unreachable();
            }
        }
    })
}

#[cfg(test)]
/// XorShiftRng
struct DeterministicRng {
    x: u32,
    y: u32,
    z: u32,
    w: u32,
}

#[cfg(test)]
impl DeterministicRng {
    fn new() -> Self {
        DeterministicRng { x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
    }

    fn next(&mut self) -> u32 {
        let x = self.x;
        let t = x ^ (x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        let w_ = self.w;
        self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
        self.w
    }
}
<commit_msg>Document btree's unwrap_unchecked<commit_after>pub mod map;
mod navigate;
mod node;
mod search;
pub mod set;

#[doc(hidden)]
trait Recover<Q: ?Sized> {
    type Key;

    fn get(&self, key: &Q) -> Option<&Self::Key>;
    fn take(&mut self, key: &Q) -> Option<Self::Key>;
    fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
}

/// Same purpose as `Option::unwrap` but doesn't always guarantee a panic
/// if the option contains no value.
/// SAFETY: the caller must ensure that the option contains a value.
#[inline(always)]
pub unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T {
    val.unwrap_or_else(|| {
        if cfg!(debug_assertions) {
            panic!("'unchecked' unwrap on None in BTreeMap");
        } else {
            unsafe {
                core::intrinsics::unreachable();
            }
        }
    })
}

#[cfg(test)]
/// XorShiftRng
struct DeterministicRng {
    x: u32,
    y: u32,
    z: u32,
    w: u32,
}

#[cfg(test)]
impl DeterministicRng {
    fn new() -> Self {
        DeterministicRng { x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
    }

    fn next(&mut self) -> u32 {
        let x = self.x;
        let t = x ^ (x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        let w_ = self.w;
        self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
        self.w
    }
}
<|endoftext|>


<commit_before>use num::Num;
use point::Point2D;
use size::Size2D;
use cmp::{Eq, Ord};

pub struct Rect<T:Copy Num> {
    origin: Point2D<T>,
    size: Size2D<T>

}

pub pure fn Rect<T:Copy Num>(origin: Point2D<T>, size: Size2D<T>) -> Rect<T> {
    return Rect {
        origin: copy origin,
        size: copy size
    }
}

impl<T: Copy Num Ord> Rect<T> {
    pure fn intersects(other: &Rect<T>) -> bool {
        self.origin.x < other.origin.x.add(&other.size.width) &&
       other.origin.x <  self.origin.x.add(&self.size.width) &&
        self.origin.y < other.origin.y.add(&other.size.height) &&
       other.origin.y <  self.origin.y.add(&self.size.height)
    }
}

impl<T: Copy Num Ord> Rect<T> {
    pure fn intersection(other: &Rect<T>) -> Option<Rect<T>> {
        if !self.intersects(other) { return None }

        Some(Rect(Point2D(max(self.origin.x, other.origin.x),
                            max(self.origin.y, other.origin.y)),
                  Size2D(min(self.origin.x.add(&self.size.width),
                            other.origin.x.add(&other.size.width)),
                         min(self.origin.y.add(&self.size.height),
                            other.origin.y.add(&other.size.height)))
        ))
    }

    pure fn union(other: &Rect<T>) -> Rect<T> {
        let upper_left = Point2D(min(self.origin.x, other.origin.x),
                                 min(self.origin.y, other.origin.y));

        let lower_right = Point2D(max(self.origin.x + self.size.width,
                                      other.origin.x + other.size.width),
                                  max(self.origin.y + self.size.height,
                                      other.origin.y + other.size.height));

        Rect {
            origin: upper_left,
            size: Size2D(lower_right.x - upper_left.x, lower_right.y - upper_left.y)
        }
    }
}

impl<T: Copy Num> Rect<T> {
    pure fn translate(other: &Point2D<T>) -> Rect<T> {
        Rect {
            origin: Point2D(self.origin.x.add(&other.x),
                            self.origin.y.add(&other.y)),
            size: copy self.size
        }
    }
}

impl<T: Copy Num Eq> Rect<T>: Eq {
    pure fn eq(other: &Rect<T>) -> bool {
        self.origin == other.origin && self.size == other.size
    }
    pure fn ne(other: &Rect<T>) -> bool {
        !self.eq(other)
    }
}

pub pure fn min<T: Copy Num Ord>(x: T, y: T) -> T {
    if x <= y { x } else { y }
}

pub pure fn max<T: Copy Num Ord>(x: T, y: T) -> T {
    if x >= y { x } else { y }
}

#[test]
fn test_min_max() {
    assert min(0, 1) == 0;
    assert min(-1.0, 0.0) == -1.0;

    assert max(0, 1) == 1;
    assert max(-1.0, 0.0) == 0.0;
}

#[test]
fn test_translate() {
    let p = Rect(Point2D(0, 0), Size2D(50, 40));
    let pp = p.translate(&Point2D(10,15));

    assert pp.size.width == 50;
    assert pp.size.height == 40;
    assert pp.origin.x == 10;
    assert pp.origin.y == 15;

    let r = Rect(Point2D(-10, -5), Size2D(50, 40));
    let rr = r.translate(&Point2D(0,-10));

    assert rr.size.width == 50;
    assert rr.size.height == 40;
    assert rr.origin.x == -10;
    assert rr.origin.y == -15;
}
<<<<<<< HEAD

#[test]
fn test_union() {
    let p = Rect(Point2D(0,0), Size2D(50, 40));
    let q = Rect(Point2D(20,20), Size2D(5, 5));
    let r = Rect(Point2D(-15, -30), Size2D(200, 15));
    let s = Rect(Point2D(20, -15), Size2D(250, 200));

    let pq = p.union(&q);
    assert pq.origin == Point2D(0, 0);
    assert pq.size == Size2D(50, 40);

    let pr = p.union(&r);
    assert pr.origin == Point2D(-15, -30);
    assert pr.size == Size2D(200, 70);

    let ps = p.union(&s);
    assert ps.origin == Point2D(0, -15);
    assert ps.size == Size2D(270, 200);

}
=======
>>>>>>> Update for newest Rust
<commit_msg>Fix botched merge<commit_after>use num::Num;
use point::Point2D;
use size::Size2D;
use cmp::{Eq, Ord};

pub struct Rect<T:Copy Num> {
    origin: Point2D<T>,
    size: Size2D<T>

}

pub pure fn Rect<T:Copy Num>(origin: Point2D<T>, size: Size2D<T>) -> Rect<T> {
    return Rect {
        origin: copy origin,
        size: copy size
    }
}

impl<T: Copy Num Ord> Rect<T> {
    pure fn intersects(other: &Rect<T>) -> bool {
        self.origin.x < other.origin.x.add(&other.size.width) &&
       other.origin.x <  self.origin.x.add(&self.size.width) &&
        self.origin.y < other.origin.y.add(&other.size.height) &&
       other.origin.y <  self.origin.y.add(&self.size.height)
    }
}

impl<T: Copy Num Ord> Rect<T> {
    pure fn intersection(other: &Rect<T>) -> Option<Rect<T>> {
        if !self.intersects(other) { return None }

        Some(Rect(Point2D(max(self.origin.x, other.origin.x),
                            max(self.origin.y, other.origin.y)),
                  Size2D(min(self.origin.x.add(&self.size.width),
                            other.origin.x.add(&other.size.width)),
                         min(self.origin.y.add(&self.size.height),
                            other.origin.y.add(&other.size.height)))
        ))
    }

    pure fn union(other: &Rect<T>) -> Rect<T> {
        let upper_left = Point2D(min(self.origin.x, other.origin.x),
                                 min(self.origin.y, other.origin.y));

        let lower_right = Point2D(max(self.origin.x + self.size.width,
                                      other.origin.x + other.size.width),
                                  max(self.origin.y + self.size.height,
                                      other.origin.y + other.size.height));

        Rect {
            origin: upper_left,
            size: Size2D(lower_right.x - upper_left.x, lower_right.y - upper_left.y)
        }
    }
}

impl<T: Copy Num> Rect<T> {
    pure fn translate(other: &Point2D<T>) -> Rect<T> {
        Rect {
            origin: Point2D(self.origin.x.add(&other.x),
                            self.origin.y.add(&other.y)),
            size: copy self.size
        }
    }
}

impl<T: Copy Num Eq> Rect<T>: Eq {
    pure fn eq(other: &Rect<T>) -> bool {
        self.origin == other.origin && self.size == other.size
    }
    pure fn ne(other: &Rect<T>) -> bool {
        !self.eq(other)
    }
}

pub pure fn min<T: Copy Num Ord>(x: T, y: T) -> T {
    if x <= y { x } else { y }
}

pub pure fn max<T: Copy Num Ord>(x: T, y: T) -> T {
    if x >= y { x } else { y }
}

#[test]
fn test_min_max() {
    assert min(0, 1) == 0;
    assert min(-1.0, 0.0) == -1.0;

    assert max(0, 1) == 1;
    assert max(-1.0, 0.0) == 0.0;
}

#[test]
fn test_translate() {
    let p = Rect(Point2D(0, 0), Size2D(50, 40));
    let pp = p.translate(&Point2D(10,15));

    assert pp.size.width == 50;
    assert pp.size.height == 40;
    assert pp.origin.x == 10;
    assert pp.origin.y == 15;

    let r = Rect(Point2D(-10, -5), Size2D(50, 40));
    let rr = r.translate(&Point2D(0,-10));

    assert rr.size.width == 50;
    assert rr.size.height == 40;
    assert rr.origin.x == -10;
    assert rr.origin.y == -15;
}

#[test]
fn test_union() {
    let p = Rect(Point2D(0,0), Size2D(50, 40));
    let q = Rect(Point2D(20,20), Size2D(5, 5));
    let r = Rect(Point2D(-15, -30), Size2D(200, 15));
    let s = Rect(Point2D(20, -15), Size2D(250, 200));

    let pq = p.union(&q);
    assert pq.origin == Point2D(0, 0);
    assert pq.size == Size2D(50, 40);

    let pr = p.union(&r);
    assert pr.origin == Point2D(-15, -30);
    assert pr.size == Size2D(200, 70);

    let ps = p.union(&s);
    assert ps.origin == Point2D(0, -15);
    assert ps.size == Size2D(270, 200);

}
<|endoftext|>


<commit_before>use std::cmp::min;
use std::env;
use std::fs::{File};
use std::io::{BufReader, BufRead};
use std::str::FromStr;
use std::str::from_utf8;
use std::path::{Path, PathBuf};
use unshare::{Command, Stdio};

use libc::{geteuid, getegid};
use libc::{uid_t, gid_t};

use config::Range;
use config::Settings;
use self::Uidmap::*;
use process_util::{env_path_find, capture_stdout};

#[derive(Clone)]
pub enum Uidmap {
    Singleton(uid_t, gid_t),
    Ranges(Vec<(uid_t, uid_t, uid_t)>, Vec<(gid_t, gid_t, gid_t)>),
}

fn read_uid_map(username: &str) -> Result<Vec<Range>,String> {
    let file = try_msg!(File::open(&Path::new("/etc/subuid")),
        "Can't open /etc/subuid: {err}");
    let mut res = Vec::new();
    let reader = BufReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try_msg!(line, "Error reading /etc/subuid: {err}");
        let parts: Vec<&str> = line[..].split(':').collect();
        if parts.len() == 0 || parts[0].trim().starts_with('#') {
            continue;
        }
        if parts.len() != 3 {
            return Err(format!("/etc/subuid:{}: Bad syntax: {:?}",
                num+1, line));
        }
        let start = FromStr::from_str(parts[1]);
        let count: Result<uid_t, _> = FromStr::from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_err() || count.is_err() {
            return Err(format!("/etc/subuid:{}: Bad syntax: {:?}",
                num+1, line));
        }
        if parts[0].eq(username) {
            let start: uid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

fn read_gid_map(username: &str) -> Result<Vec<Range>,String> {
    let file = try_msg!(File::open(&Path::new("/etc/subgid")),
        "Can't open /etc/subgid: {err}");
    let mut res = Vec::new();
    let reader = BufReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try_msg!(line, "Error reading /etc/subgid: {err}");
        let parts: Vec<&str> = line[..].split(':').collect();
        if parts.len() == 0 || parts[0].trim().starts_with('#') {
            continue;
        }
        if parts.len() != 3 {
            return Err(format!("/etc/subgid:{}: Bad syntax: {:?}",
                num+1, line));
        }
        let start = FromStr::from_str(parts[1]);
        let count: Result<uid_t, _> = FromStr::from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_err() || count.is_err() {
            return Err(format!("/etc/subgid:{}: Bad syntax", num+1));
        }
        if parts[0].eq(username) {
            let start: gid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

pub fn match_ranges(req: &Vec<Range>, allowed: &Vec<Range>, own_id: uid_t)
    -> Result<Vec<(uid_t, uid_t, uid_t)>, ()>
{
    let mut res = vec!((0, own_id, 1));
    let mut reqiter = req.iter();
    let mut reqval = *reqiter.next().unwrap();
    let mut allowiter = allowed.iter();
    let mut allowval = *allowiter.next().unwrap();
    loop {
        if reqval.start() == 0 {
            reqval = reqval.shift(1);
        }
        if allowval.start() == 0 {
            allowval = allowval.shift(1);
        }
        let clen = min(reqval.len(), allowval.len());
        if clen > 0 {
            res.push((reqval.start(), allowval.start(), clen));
        }
        reqval = reqval.shift(clen);
        allowval = allowval.shift(clen);
        if reqval.len() == 0 {
            reqval = match reqiter.next() {
                Some(val) => *val,
                None => break,
            };
        }
        if allowval.len() == 0 {
            allowval = match allowiter.next() {
                Some(val) => *val,
                None => return Err(()),
            };
        }
    }
    return Ok(res);
}

pub fn get_max_uidmap() -> Result<Uidmap, String>
{
    let mut cmd = Command::new(env_path_find("id")
                               .unwrap_or(PathBuf::from("/usr/bin/id")));
    cmd.arg("-u").arg("-n");
    if let Ok(path) = env::var("_VAGGA_PATH") {
        cmd.env("PATH", path);
    }
    cmd.stdin(Stdio::null()).stderr(Stdio::inherit());
    let username = try!(capture_stdout(cmd)
        .map_err(|e| format!("Error running `id -u -n`: {}", e))
        .and_then(|val| from_utf8(&val).map(|x| x.trim().to_string())
                   .map_err(|e| format!("Can't decode username: {}", e))));
    let uid_map = read_uid_map(&username)
        .map_err(|e| error!("Error reading uidmap: {}", e));
    let gid_map = read_gid_map(&username)
        .map_err(|e| error!("Error reading gidmap: {}", e));

    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };
    if let (Ok(uid_map), Ok(gid_map)) = (uid_map, gid_map) {
        if uid_map.len() == 0 && gid_map.len() == 0 && uid == 0 {
            let uid_rng = try!(read_uid_ranges("/proc/self/uid_map", true));
            let gid_rng = try!(read_uid_ranges("/proc/self/gid_map", true));
            return Ok(Ranges(
                uid_rng.into_iter()
                    .map(|r| (r.start(), r.start(), r.len())).collect(),
                gid_rng.into_iter()
                    .map(|r| (r.start(), r.start(), r.len())).collect()));
        }
        let mut uids = vec!((0, uid, 1));
        for &rng in uid_map.iter() {
            let mut rng = rng;
            if uid >= rng.start() && uid <= rng.end() {
                // TODO(tailhook) implement better heuristic
                assert!(uid == rng.start());
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            uids.push((rng.start(), rng.start(), rng.len()));
        }

        let mut gids = vec!((0, gid, 1));
        for &rng in gid_map.iter() {
            let mut rng = rng;
            if gid >= rng.start() && gid <= rng.end() {
                // TODO(tailhook) implement better heuristic
                assert!(gid == rng.start());
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            gids.push((rng.start(), rng.start(), rng.len()));
        }

        return Ok(Ranges(uids, gids));
    } else {
        warn!("Could not read /etc/subuid or /etc/subgid \
            (see http://bit.ly/err_subuid)");
        return Ok(Singleton(uid, gid));
    }
}

fn read_uid_ranges(path: &str, read_inside: bool) -> Result<Vec<Range>, String>
{
    let file = BufReader::new(try!(File::open(&Path::new(path))
        .map_err(|e| format!("Error reading uid/gid map: {}", e))));
    let mut result = vec!();
    for line in file.lines() {
        let line = try!(line
            .map_err(|_| format!("Error reading uid/gid map")));
        let mut words = line[..].split_whitespace();
        let inside: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let outside: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let count: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        if read_inside {
            result.push(Range::new(inside, inside+count-1));
        } else {
            result.push(Range::new(outside, outside+count-1));
        }
    }
    return Ok(result);
}

pub fn map_users(settings: &Settings, uids: &Vec<Range>, gids: &Vec<Range>)
    -> Result<Uidmap, String>
{
    let default_uids = vec!(Range::new(0, 0));
    let default_gids = vec!(Range::new(0, 0));
    let uids = if uids.len() > 0 { uids } else { &default_uids };
    let gids = if gids.len() > 0 { gids } else { &default_gids };
    match settings.uid_map {
        None => {
            let ranges = try!(read_uid_ranges("/proc/self/uid_map", true));
            let uid_map = try!(match_ranges(uids, &ranges, 0)
                .map_err(|()| {
                    return format!("Number of allowed subuids is too small. \
                        Required {:?}, allowed {:?}. You either need to increase \
                        allowed numbers in /etc/subuid (preferred) or decrease \
                        needed ranges in vagga.yaml by adding `uids` key \
                        to container config", uids, ranges);
                }));
            let ranges = try!(read_uid_ranges("/proc/self/gid_map", true));
            let gid_map = try!(match_ranges(gids, &ranges, 0)
                .map_err(|()| {
                    return format!("Number of allowed subgids is too small. \
                        Required {:?}, allowed {:?}. You either need to increase \
                        allowed numbers in /etc/subgid (preferred) or decrease \
                        needed ranges in vagga.yaml by adding `gids` key \
                        to container config", gids, ranges);
                }));
            Ok(Ranges(uid_map, gid_map))
        },
        Some((ref uids, ref gids)) => {
            Ok(Ranges(uids.clone(), gids.clone()))
        }
    }
}
<commit_msg>Folded almost identical functions: read_uid_map & read_gid_map<commit_after>use std::cmp::min;
use std::env;
use std::fs::{File};
use std::io::{BufReader, BufRead};
use std::str::FromStr;
use std::str::from_utf8;
use std::path::{Path, PathBuf};
use unshare::{Command, Stdio};

use libc::{geteuid, getegid};
use libc::{uid_t, gid_t};

use config::Range;
use config::Settings;
use self::Uidmap::*;
use process_util::{env_path_find, capture_stdout};

#[derive(Clone)]
pub enum Uidmap {
    Singleton(uid_t, gid_t),
    Ranges(Vec<(uid_t, uid_t, uid_t)>, Vec<(gid_t, gid_t, gid_t)>),
}

fn read_uid_map(file_path: &str, username: &str) -> Result<Vec<Range>,String> {
    let file = try_msg!(File::open(&Path::new(file_path)),
        "Can't open {path}: {err}", path=file_path);
    let mut res = Vec::new();
    let reader = BufReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try_msg!(line, "Error reading {path}: {err}", path=file_path);
        let parts: Vec<&str> = line[..].split(':').collect();
        if parts.len() == 0 || parts[0].trim().starts_with('#') {
            continue;
        }
        if parts.len() != 3 {
            return Err(format!("{}:{}: Bad syntax: {:?}",
                file_path, num+1, line));
        }
        let start = FromStr::from_str(parts[1]);
        let count: Result<uid_t, _> = FromStr::from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_err() || count.is_err() {
            return Err(format!("{}:{}: Bad syntax: {:?}",
                file_path, num+1, line));
        }
        if parts[0].eq(username) {
            let start: uid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

pub fn match_ranges(req: &Vec<Range>, allowed: &Vec<Range>, own_id: uid_t)
    -> Result<Vec<(uid_t, uid_t, uid_t)>, ()>
{
    let mut res = vec!((0, own_id, 1));
    let mut reqiter = req.iter();
    let mut reqval = *reqiter.next().unwrap();
    let mut allowiter = allowed.iter();
    let mut allowval = *allowiter.next().unwrap();
    loop {
        if reqval.start() == 0 {
            reqval = reqval.shift(1);
        }
        if allowval.start() == 0 {
            allowval = allowval.shift(1);
        }
        let clen = min(reqval.len(), allowval.len());
        if clen > 0 {
            res.push((reqval.start(), allowval.start(), clen));
        }
        reqval = reqval.shift(clen);
        allowval = allowval.shift(clen);
        if reqval.len() == 0 {
            reqval = match reqiter.next() {
                Some(val) => *val,
                None => break,
            };
        }
        if allowval.len() == 0 {
            allowval = match allowiter.next() {
                Some(val) => *val,
                None => return Err(()),
            };
        }
    }
    return Ok(res);
}

pub fn get_max_uidmap() -> Result<Uidmap, String>
{
    let mut cmd = Command::new(env_path_find("id")
                               .unwrap_or(PathBuf::from("/usr/bin/id")));
    cmd.arg("-u").arg("-n");
    if let Ok(path) = env::var("_VAGGA_PATH") {
        cmd.env("PATH", path);
    }
    cmd.stdin(Stdio::null()).stderr(Stdio::inherit());
    let username = try!(capture_stdout(cmd)
        .map_err(|e| format!("Error running `id -u -n`: {}", e))
        .and_then(|val| from_utf8(&val).map(|x| x.trim().to_string())
                   .map_err(|e| format!("Can't decode username: {}", e))));
    let uid_map = read_uid_map("/etc/subuid", &username)
        .map_err(|e| error!("Error reading uidmap: {}", e));
    let gid_map = read_uid_map("/etc/subgid", &username)
        .map_err(|e| error!("Error reading gidmap: {}", e));

    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };
    if let (Ok(uid_map), Ok(gid_map)) = (uid_map, gid_map) {
        if uid_map.len() == 0 && gid_map.len() == 0 && uid == 0 {
            let uid_rng = try!(read_uid_ranges("/proc/self/uid_map", true));
            let gid_rng = try!(read_uid_ranges("/proc/self/gid_map", true));
            return Ok(Ranges(
                uid_rng.into_iter()
                    .map(|r| (r.start(), r.start(), r.len())).collect(),
                gid_rng.into_iter()
                    .map(|r| (r.start(), r.start(), r.len())).collect()));
        }
        let mut uids = vec!((0, uid, 1));
        for &rng in uid_map.iter() {
            let mut rng = rng;
            if uid >= rng.start() && uid <= rng.end() {
                // TODO(tailhook) implement better heuristic
                assert!(uid == rng.start());
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            uids.push((rng.start(), rng.start(), rng.len()));
        }

        let mut gids = vec!((0, gid, 1));
        for &rng in gid_map.iter() {
            let mut rng = rng;
            if gid >= rng.start() && gid <= rng.end() {
                // TODO(tailhook) implement better heuristic
                assert!(gid == rng.start());
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            gids.push((rng.start(), rng.start(), rng.len()));
        }

        return Ok(Ranges(uids, gids));
    } else {
        warn!("Could not read /etc/subuid or /etc/subgid \
            (see http://bit.ly/err_subuid)");
        return Ok(Singleton(uid, gid));
    }
}

fn read_uid_ranges(path: &str, read_inside: bool) -> Result<Vec<Range>, String>
{
    let file = BufReader::new(try!(File::open(&Path::new(path))
        .map_err(|e| format!("Error reading uid/gid map: {}", e))));
    let mut result = vec!();
    for line in file.lines() {
        let line = try!(line
            .map_err(|_| format!("Error reading uid/gid map")));
        let mut words = line[..].split_whitespace();
        let inside: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let outside: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let count: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        if read_inside {
            result.push(Range::new(inside, inside+count-1));
        } else {
            result.push(Range::new(outside, outside+count-1));
        }
    }
    return Ok(result);
}

pub fn map_users(settings: &Settings, uids: &Vec<Range>, gids: &Vec<Range>)
    -> Result<Uidmap, String>
{
    let default_uids = vec!(Range::new(0, 0));
    let default_gids = vec!(Range::new(0, 0));
    let uids = if uids.len() > 0 { uids } else { &default_uids };
    let gids = if gids.len() > 0 { gids } else { &default_gids };
    match settings.uid_map {
        None => {
            let ranges = try!(read_uid_ranges("/proc/self/uid_map", true));
            let uid_map = try!(match_ranges(uids, &ranges, 0)
                .map_err(|()| {
                    return format!("Number of allowed subuids is too small. \
                        Required {:?}, allowed {:?}. You either need to increase \
                        allowed numbers in /etc/subuid (preferred) or decrease \
                        needed ranges in vagga.yaml by adding `uids` key \
                        to container config", uids, ranges);
                }));
            let ranges = try!(read_uid_ranges("/proc/self/gid_map", true));
            let gid_map = try!(match_ranges(gids, &ranges, 0)
                .map_err(|()| {
                    return format!("Number of allowed subgids is too small. \
                        Required {:?}, allowed {:?}. You either need to increase \
                        allowed numbers in /etc/subgid (preferred) or decrease \
                        needed ranges in vagga.yaml by adding `gids` key \
                        to container config", gids, ranges);
                }));
            Ok(Ranges(uid_map, gid_map))
        },
        Some((ref uids, ref gids)) => {
            Ok(Ranges(uids.clone(), gids.clone()))
        }
    }
}
<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.pc=cpu_state.pc+1;
    }
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState,mut mem:&Memory) {
    }
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        self.execute(cpu_state,mem);
    }

    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => { },
            AddressMode::AbsoluteY       => { },
            AddressMode::Accumulator     => { },
            AddressMode::Immediate       => { },
            AddressMode::Implied         => { },
            AddressMode::Indirect        => { },
            AddressMode::IndexedIndirect => { },
            AddressMode::IndirectIndexed => { },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {},
            AddressMode::ZeroPageY       => { },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }
}

<commit_msg>fetch_and_decode now calls decode and moves pc properly<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u8,OpcodeExecInfo>,
}

impl CpuExecutor {
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u8, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = self.decode(cpu_state,mem);

        cpu_state.pc = cpu_state.pc + cpu_state.decode_register.info.len as u16;
    }
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState,mut mem:&Memory) {
    }
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        self.execute(cpu_state,mem);
    }

    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> DecodeRegister {
        let mut dr = DecodeRegister {
            info : self.op_table[&cpu_state.instruction_register].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => { },
            AddressMode::AbsoluteY       => { },
            AddressMode::Accumulator     => { },
            AddressMode::Immediate       => { },
            AddressMode::Implied         => { },
            AddressMode::Indirect        => { },
            AddressMode::IndexedIndirect => { },
            AddressMode::IndirectIndexed => { },
            AddressMode::Relative        => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {},
            AddressMode::ZeroPageY       => { },
            _ => panic!("unrecognized addressing mode while decoding instruction_register!")
        }

        return dr;
    }
}

<|endoftext|>


<commit_before>use std::{
    collections::BTreeMap,
    convert::{TryFrom, TryInto},
    fmt,
};

use js_int::Int;
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
use serde_json::{to_string as to_json_string, Value as JsonValue};

use super::Error;

/// The inner type of `CanonicalJsonValue::Object`.
pub type Object = BTreeMap<String, CanonicalJsonValue>;

/// Represents a canonical JSON value as per the Matrix specification.
#[derive(Clone, Eq, PartialEq)]
pub enum CanonicalJsonValue {
    /// Represents a JSON null value.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(null).try_into().unwrap();
    /// ```
    Null,

    /// Represents a JSON boolean.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(true).try_into().unwrap();
    /// ```
    Bool(bool),

    /// Represents a JSON integer.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(12).try_into().unwrap();
    /// ```
    Integer(Int),

    /// Represents a JSON string.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!("a string").try_into().unwrap();
    /// ```
    String(String),

    /// Represents a JSON array.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(["an", "array"]).try_into().unwrap();
    /// ```
    Array(Vec<CanonicalJsonValue>),

    /// Represents a JSON object.
    ///
    /// The map is backed by a BTreeMap to guarantee the sorting of keys.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!({ "an": "object" }).try_into().unwrap();
    /// ```
    Object(Object),
}

impl CanonicalJsonValue {
    /// If the `CanonicalJsonValue` is a `Bool`, return the inner value.
    pub fn as_bool(&self) -> Option<bool> {
        match self {
            Self::Bool(b) => Some(*b),
            _ => None,
        }
    }

    /// If the `CanonicalJsonValue` is an `Integer`, return the inner value.
    pub fn as_integer(&self) -> Option<Int> {
        match self {
            Self::Integer(i) => Some(*i),
            _ => None,
        }
    }

    /// If the `CanonicalJsonValue` is a `String`, return a reference to the inner value.
    pub fn as_str(&self) -> Option<&str> {
        match self {
            Self::String(s) => Some(s),
            _ => None,
        }
    }

    /// If the `CanonicalJsonValue` is an `Array`, return a reference to the inner value.
    pub fn as_array(&self) -> Option<&[CanonicalJsonValue]> {
        match self {
            Self::Array(a) => Some(a),
            _ => None,
        }
    }

    /// If the `CanonicalJsonValue` is an `Object`, return a reference to the inner value.
    pub fn as_object(&self) -> Option<&Object> {
        match self {
            Self::Object(o) => Some(o),
            _ => None,
        }
    }
}

impl Default for CanonicalJsonValue {
    fn default() -> Self {
        Self::Null
    }
}

impl fmt::Debug for CanonicalJsonValue {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Self::Null => formatter.debug_tuple("Null").finish(),
            Self::Bool(v) => formatter.debug_tuple("Bool").field(&v).finish(),
            Self::Integer(ref v) => fmt::Debug::fmt(v, formatter),
            Self::String(ref v) => formatter.debug_tuple("String").field(v).finish(),
            Self::Array(ref v) => {
                formatter.write_str("Array(")?;
                fmt::Debug::fmt(v, formatter)?;
                formatter.write_str(")")
            }
            Self::Object(ref v) => {
                formatter.write_str("Object(")?;
                fmt::Debug::fmt(v, formatter)?;
                formatter.write_str(")")
            }
        }
    }
}

impl fmt::Display for CanonicalJsonValue {
    /// Display this value as a string.
    ///
    /// This `Display` implementation is intentionally unaffected by any formatting parameters,
    /// because adding extra whitespace or otherwise pretty-printing it would make it not the
    /// canonical form anymore.
    ///
    /// If you want to pretty-print a `CanonicalJsonValue` for debugging purposes, use
    /// one of `serde_json::{to_string_pretty, to_vec_pretty, to_writer_pretty}`.
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", to_json_string(&self).map_err(|_| fmt::Error)?)
    }
}

impl TryFrom<JsonValue> for CanonicalJsonValue {
    type Error = Error;

    fn try_from(val: JsonValue) -> Result<Self, Self::Error> {
        Ok(match val {
            JsonValue::Bool(b) => Self::Bool(b),
            JsonValue::Number(num) => Self::Integer(
                Int::try_from(num.as_i64().ok_or(Error::IntConvert)?)
                    .map_err(|_| Error::IntConvert)?,
            ),
            JsonValue::Array(vec) => {
                Self::Array(vec.into_iter().map(TryInto::try_into).collect::<Result<Vec<_>, _>>()?)
            }
            JsonValue::String(string) => Self::String(string),
            JsonValue::Object(obj) => Self::Object(
                obj.into_iter()
                    .map(|(k, v)| Ok((k, v.try_into()?)))
                    .collect::<Result<Object, _>>()?,
            ),
            JsonValue::Null => Self::Null,
        })
    }
}

impl From<CanonicalJsonValue> for JsonValue {
    fn from(val: CanonicalJsonValue) -> Self {
        match val {
            CanonicalJsonValue::Bool(b) => Self::Bool(b),
            CanonicalJsonValue::Integer(int) => Self::Number(i64::from(int).into()),
            CanonicalJsonValue::String(string) => Self::String(string),
            CanonicalJsonValue::Array(vec) => {
                Self::Array(vec.into_iter().map(Into::into).collect())
            }
            CanonicalJsonValue::Object(obj) => {
                Self::Object(obj.into_iter().map(|(k, v)| (k, v.into())).collect())
            }
            CanonicalJsonValue::Null => Self::Null,
        }
    }
}

impl Serialize for CanonicalJsonValue {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match self {
            Self::Null => serializer.serialize_unit(),
            Self::Bool(b) => serializer.serialize_bool(*b),
            Self::Integer(n) => n.serialize(serializer),
            Self::String(s) => serializer.serialize_str(s),
            Self::Array(v) => v.serialize(serializer),
            Self::Object(m) => {
                use serde::ser::SerializeMap;
                let mut map = serializer.serialize_map(Some(m.len()))?;
                for (k, v) in m {
                    map.serialize_entry(k, v)?;
                }
                map.end()
            }
        }
    }
}

impl<'de> Deserialize<'de> for CanonicalJsonValue {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<CanonicalJsonValue, D::Error>
    where
        D: Deserializer<'de>,
    {
        let val = JsonValue::deserialize(deserializer)?;
        val.try_into().map_err(serde::de::Error::custom)
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;

    use serde_json::json;

    use super::CanonicalJsonValue;

    #[test]
    fn to_string() {
        const CANONICAL_STR: &str = r#"{"city":"London","street":"10 Downing Street"}"#;

        let json: CanonicalJsonValue =
            json!({ "city": "London", "street": "10 Downing Street" }).try_into().unwrap();

        assert_eq!(format!("{}", json), CANONICAL_STR);
        assert_eq!(format!("{:#}", json), CANONICAL_STR);
    }
}
<commit_msg>serde: Add as_array_mut and as_object_mut methods to CanonicalJsonValue<commit_after>use std::{
    collections::BTreeMap,
    convert::{TryFrom, TryInto},
    fmt,
};

use js_int::Int;
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
use serde_json::{to_string as to_json_string, Value as JsonValue};

use super::Error;

/// The inner type of `CanonicalJsonValue::Object`.
pub type Object = BTreeMap<String, CanonicalJsonValue>;

/// Represents a canonical JSON value as per the Matrix specification.
#[derive(Clone, Eq, PartialEq)]
pub enum CanonicalJsonValue {
    /// Represents a JSON null value.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(null).try_into().unwrap();
    /// ```
    Null,

    /// Represents a JSON boolean.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(true).try_into().unwrap();
    /// ```
    Bool(bool),

    /// Represents a JSON integer.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(12).try_into().unwrap();
    /// ```
    Integer(Int),

    /// Represents a JSON string.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!("a string").try_into().unwrap();
    /// ```
    String(String),

    /// Represents a JSON array.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!(["an", "array"]).try_into().unwrap();
    /// ```
    Array(Vec<CanonicalJsonValue>),

    /// Represents a JSON object.
    ///
    /// The map is backed by a BTreeMap to guarantee the sorting of keys.
    ///
    /// ```
    /// # use serde_json::json;
    /// # use std::convert::TryInto;
    /// # use ruma_serde::CanonicalJsonValue;
    /// let v: CanonicalJsonValue = json!({ "an": "object" }).try_into().unwrap();
    /// ```
    Object(Object),
}

impl CanonicalJsonValue {
    /// If the `CanonicalJsonValue` is a `Bool`, return the inner value.
    pub fn as_bool(&self) -> Option<bool> {
        match self {
            Self::Bool(b) => Some(*b),
            _ => None,
        }
    }

    /// If the `CanonicalJsonValue` is an `Integer`, return the inner value.
    pub fn as_integer(&self) -> Option<Int> {
        match self {
            Self::Integer(i) => Some(*i),
            _ => None,
        }
    }

    /// If the `CanonicalJsonValue` is a `String`, return a reference to the inner value.
    pub fn as_str(&self) -> Option<&str> {
        match self {
            Self::String(s) => Some(s),
            _ => None,
        }
    }

    /// If the `CanonicalJsonValue` is an `Array`, return a reference to the inner value.
    pub fn as_array(&self) -> Option<&[CanonicalJsonValue]> {
        match self {
            Self::Array(a) => Some(a),
            _ => None,
        }
    }

    /// If the `CanonicalJsonValue` is an `Object`, return a reference to the inner value.
    pub fn as_object(&self) -> Option<&Object> {
        match self {
            Self::Object(o) => Some(o),
            _ => None,
        }
    }

    /// If the `CanonicalJsonValue` is an `Array`, return a mutable reference to the inner value.
    pub fn as_array_mut(&mut self) -> Option<&mut Vec<CanonicalJsonValue>> {
        match self {
            Self::Array(a) => Some(a),
            _ => None,
        }
    }

    /// If the `CanonicalJsonValue` is an `Object`, return a mutable reference to the inner value.
    pub fn as_object_mut(&mut self) -> Option<&mut Object> {
        match self {
            Self::Object(o) => Some(o),
            _ => None,
        }
    }
}

impl Default for CanonicalJsonValue {
    fn default() -> Self {
        Self::Null
    }
}

impl fmt::Debug for CanonicalJsonValue {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Self::Null => formatter.debug_tuple("Null").finish(),
            Self::Bool(v) => formatter.debug_tuple("Bool").field(&v).finish(),
            Self::Integer(ref v) => fmt::Debug::fmt(v, formatter),
            Self::String(ref v) => formatter.debug_tuple("String").field(v).finish(),
            Self::Array(ref v) => {
                formatter.write_str("Array(")?;
                fmt::Debug::fmt(v, formatter)?;
                formatter.write_str(")")
            }
            Self::Object(ref v) => {
                formatter.write_str("Object(")?;
                fmt::Debug::fmt(v, formatter)?;
                formatter.write_str(")")
            }
        }
    }
}

impl fmt::Display for CanonicalJsonValue {
    /// Display this value as a string.
    ///
    /// This `Display` implementation is intentionally unaffected by any formatting parameters,
    /// because adding extra whitespace or otherwise pretty-printing it would make it not the
    /// canonical form anymore.
    ///
    /// If you want to pretty-print a `CanonicalJsonValue` for debugging purposes, use
    /// one of `serde_json::{to_string_pretty, to_vec_pretty, to_writer_pretty}`.
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", to_json_string(&self).map_err(|_| fmt::Error)?)
    }
}

impl TryFrom<JsonValue> for CanonicalJsonValue {
    type Error = Error;

    fn try_from(val: JsonValue) -> Result<Self, Self::Error> {
        Ok(match val {
            JsonValue::Bool(b) => Self::Bool(b),
            JsonValue::Number(num) => Self::Integer(
                Int::try_from(num.as_i64().ok_or(Error::IntConvert)?)
                    .map_err(|_| Error::IntConvert)?,
            ),
            JsonValue::Array(vec) => {
                Self::Array(vec.into_iter().map(TryInto::try_into).collect::<Result<Vec<_>, _>>()?)
            }
            JsonValue::String(string) => Self::String(string),
            JsonValue::Object(obj) => Self::Object(
                obj.into_iter()
                    .map(|(k, v)| Ok((k, v.try_into()?)))
                    .collect::<Result<Object, _>>()?,
            ),
            JsonValue::Null => Self::Null,
        })
    }
}

impl From<CanonicalJsonValue> for JsonValue {
    fn from(val: CanonicalJsonValue) -> Self {
        match val {
            CanonicalJsonValue::Bool(b) => Self::Bool(b),
            CanonicalJsonValue::Integer(int) => Self::Number(i64::from(int).into()),
            CanonicalJsonValue::String(string) => Self::String(string),
            CanonicalJsonValue::Array(vec) => {
                Self::Array(vec.into_iter().map(Into::into).collect())
            }
            CanonicalJsonValue::Object(obj) => {
                Self::Object(obj.into_iter().map(|(k, v)| (k, v.into())).collect())
            }
            CanonicalJsonValue::Null => Self::Null,
        }
    }
}

impl Serialize for CanonicalJsonValue {
    #[inline]
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match self {
            Self::Null => serializer.serialize_unit(),
            Self::Bool(b) => serializer.serialize_bool(*b),
            Self::Integer(n) => n.serialize(serializer),
            Self::String(s) => serializer.serialize_str(s),
            Self::Array(v) => v.serialize(serializer),
            Self::Object(m) => {
                use serde::ser::SerializeMap;
                let mut map = serializer.serialize_map(Some(m.len()))?;
                for (k, v) in m {
                    map.serialize_entry(k, v)?;
                }
                map.end()
            }
        }
    }
}

impl<'de> Deserialize<'de> for CanonicalJsonValue {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<CanonicalJsonValue, D::Error>
    where
        D: Deserializer<'de>,
    {
        let val = JsonValue::deserialize(deserializer)?;
        val.try_into().map_err(serde::de::Error::custom)
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;

    use serde_json::json;

    use super::CanonicalJsonValue;

    #[test]
    fn to_string() {
        const CANONICAL_STR: &str = r#"{"city":"London","street":"10 Downing Street"}"#;

        let json: CanonicalJsonValue =
            json!({ "city": "London", "street": "10 Downing Street" }).try_into().unwrap();

        assert_eq!(format!("{}", json), CANONICAL_STR);
        assert_eq!(format!("{:#}", json), CANONICAL_STR);
    }
}
<|endoftext|>