<commit_before>use rustc::mir::*;
use rustc::ty::{self, adjustment::PointerCast, Predicate, Ty, TyCtxt};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use std::borrow::Cow;
use syntax::attr;

type McfResult = Result<(), (Span, Cow<'static, str>)>;

pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -> McfResult {
    let mut current = def_id;
    loop {
        let predicates = tcx.predicates_of(current);
        for (predicate, _) in predicates.predicates {
            match predicate {
                Predicate::RegionOutlives(_)
                | Predicate::TypeOutlives(_)
                | Predicate::WellFormed(_)
                | Predicate::Projection(_)
                | Predicate::ConstEvaluatable(..) => continue,
                Predicate::ObjectSafe(_) => {
                    bug!("object safe predicate on function: {:#?}", predicate)
                }
                Predicate::ClosureKind(..) => {
                    bug!("closure kind predicate on function: {:#?}", predicate)
                }
                Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
                Predicate::Trait(pred) => {
                    if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                        continue;
                    }
                    match pred.skip_binder().self_ty().kind {
                        ty::Param(ref p) => {
                            let generics = tcx.generics_of(current);
                            let def = generics.type_param(p, tcx);
                            let span = tcx.def_span(def.def_id);
                            return Err((
                                span,
                                "trait bounds other than `Sized` \
                                 on const fn parameters are unstable"
                                    .into(),
                            ));
                        }
                        // other kinds of bounds are either tautologies
                        // or cause errors in other passes
                        _ => continue,
                    }
                }
            }
        }
        match predicates.parent {
            Some(parent) => current = parent,
            None => break,
        }
    }

    for local in &body.local_decls {
        check_ty(tcx, local.ty, local.source_info.span, def_id)?;
    }
    // impl trait is gone in MIR, so check the return type manually
    check_ty(
        tcx,
        tcx.fn_sig(def_id).output().skip_binder(),
        body.local_decls.iter().next().unwrap().source_info.span,
        def_id,
    )?;

    for bb in body.basic_blocks() {
        check_terminator(tcx, body, def_id, bb.terminator())?;
        for stmt in &bb.statements {
            check_statement(tcx, body, def_id, stmt)?;
        }
    }
    Ok(())
}

fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult {
    for ty in ty.walk() {
        match ty.kind {
            ty::Ref(_, _, hir::Mutability::Mut) => {
                if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) {
                    return Err((span, "mutable references in const fn are unstable".into()));
                }
            }
            ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
            ty::FnPtr(..) => {
                if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) {
                    return Err((span, "function pointers in const fn are unstable".into()));
                }
            }
            ty::Dynamic(preds, _) => {
                for pred in preds.iter() {
                    match pred.skip_binder() {
                        ty::ExistentialPredicate::AutoTrait(_)
                        | ty::ExistentialPredicate::Projection(_) => {
                            return Err((
                                span,
                                "trait bounds other than `Sized` \
                                 on const fn parameters are unstable"
                                    .into(),
                            ));
                        }
                        ty::ExistentialPredicate::Trait(trait_ref) => {
                            if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
                                return Err((
                                    span,
                                    "trait bounds other than `Sized` \
                                     on const fn parameters are unstable"
                                        .into(),
                                ));
                            }
                        }
                    }
                }
            }
            _ => {}
        }
    }
    Ok(())
}

fn check_rvalue(
    tcx: TyCtxt<'tcx>,
    body: &Body<'tcx>,
    def_id: DefId,
    rvalue: &Rvalue<'tcx>,
    span: Span,
) -> McfResult {
    match rvalue {
        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
            check_operand(tcx, operand, span, def_id, body)
        }
        Rvalue::Len(place)
        | Rvalue::Discriminant(place)
        | Rvalue::Ref(_, _, place)
        | Rvalue::AddressOf(_, place) => check_place(tcx, place, span, def_id, body),
        Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
            use rustc::ty::cast::CastTy;
            let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");
            let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
            match (cast_in, cast_out) {
                (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => {
                    Err((span, "casting pointers to ints is unstable in const fn".into()))
                }
                _ => check_operand(tcx, operand, span, def_id, body),
            }
        }
        Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _)
        | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, _) => {
            check_operand(tcx, operand, span, def_id, body)
        }
        Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _)
        | Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), _, _)
        | Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), _, _) => {
            Err((span, "function pointer casts are not allowed in const fn".into()))
        }
        Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
            Err((span, "unsizing casts are not allowed in const fn".into()))
        }
        // binops are fine on integers
        Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
            check_operand(tcx, lhs, span, def_id, body)?;
            check_operand(tcx, rhs, span, def_id, body)?;
            let ty = lhs.ty(body, tcx);
            if ty.is_integral() || ty.is_bool() || ty.is_char() {
                Ok(())
            } else {
                Err((span, "only int, `bool` and `char` operations are stable in const fn".into()))
            }
        }
        Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()),
        Rvalue::NullaryOp(NullOp::Box, _) => {
            Err((span, "heap allocations are not allowed in const fn".into()))
        }
        Rvalue::UnaryOp(_, operand) => {
            let ty = operand.ty(body, tcx);
            if ty.is_integral() || ty.is_bool() {
                check_operand(tcx, operand, span, def_id, body)
            } else {
                Err((span, "only int and `bool` operations are stable in const fn".into()))
            }
        }
        Rvalue::Aggregate(_, operands) => {
            for operand in operands {
                check_operand(tcx, operand, span, def_id, body)?;
            }
            Ok(())
        }
    }
}

fn check_statement(
    tcx: TyCtxt<'tcx>,
    body: &Body<'tcx>,
    def_id: DefId,
    statement: &Statement<'tcx>,
) -> McfResult {
    let span = statement.source_info.span;
    match &statement.kind {
        StatementKind::Assign(box (place, rval)) => {
            check_place(tcx, place, span, def_id, body)?;
            check_rvalue(tcx, body, def_id, rval, span)
        }

        StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
            if !feature_allowed(tcx, def_id, sym::const_if_match) =>
        {
            Err((span, "loops and conditional expressions are not stable in const fn".into()))
        }

        StatementKind::FakeRead(_, place) => check_place(tcx, place, span, def_id, body),

        // just an assignment
        StatementKind::SetDiscriminant { place, .. } => check_place(tcx, place, span, def_id, body),

        StatementKind::InlineAsm { .. } => {
            Err((span, "cannot use inline assembly in const fn".into()))
        }

        // These are all NOPs
        StatementKind::StorageLive(_)
        | StatementKind::StorageDead(_)
        | StatementKind::Retag { .. }
        | StatementKind::AscribeUserType(..)
        | StatementKind::Nop => Ok(()),
    }
}

fn check_operand(
    tcx: TyCtxt<'tcx>,
    operand: &Operand<'tcx>,
    span: Span,
    def_id: DefId,
    body: &Body<'tcx>,
) -> McfResult {
    match operand {
        Operand::Move(place) | Operand::Copy(place) => check_place(tcx, place, span, def_id, body),
        Operand::Constant(c) => match c.check_static_ptr(tcx) {
            Some(_) => Err((span, "cannot access `static` items in const fn".into())),
            None => Ok(()),
        },
    }
}

fn check_place(
    tcx: TyCtxt<'tcx>,
    place: &Place<'tcx>,
    span: Span,
    def_id: DefId,
    body: &Body<'tcx>,
) -> McfResult {
    let mut cursor = place.projection.as_ref();
    while let &[ref proj_base @ .., elem] = cursor {
        cursor = proj_base;
        match elem {
            ProjectionElem::Downcast(..) if !feature_allowed(tcx, def_id, sym::const_if_match) => {
                return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
            }
            ProjectionElem::Downcast(_symbol, _variant_index) => {}

            ProjectionElem::Field(..) => {
                let base_ty = Place::ty_from(&place.base, &proj_base, body, tcx).ty;
                if let Some(def) = base_ty.ty_adt_def() {
                    // No union field accesses in `const fn`
                    if def.is_union() {
                        if !feature_allowed(tcx, def_id, sym::const_fn_union) {
                            return Err((span, "accessing union fields is unstable".into()));
                        }
                    }
                }
            }
            ProjectionElem::ConstantIndex { .. }
            | ProjectionElem::Subslice { .. }
            | ProjectionElem::Deref
            | ProjectionElem::Index(_) => {}
        }
    }

    Ok(())
}

/// Returns `true` if the given feature gate is allowed within the function with the given `DefId`.
fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool {
    // All features require that the corresponding gate be enabled.
    if !tcx.features().enabled(feature_gate) {
        return false;
    }

    // If this crate is not using stability attributes, or this function is not claiming to be a
    // stable `const fn`, that is all that is required.
    if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
        return true;
    }

    // However, we cannot allow stable `const fn`s to use unstable features without an explicit
    // opt-in via `allow_internal_unstable`.
    attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
        .map_or(false, |mut features| features.any(|name| name == feature_gate))
}

fn check_terminator(
    tcx: TyCtxt<'tcx>,
    body: &'a Body<'tcx>,
    def_id: DefId,
    terminator: &Terminator<'tcx>,
) -> McfResult {
    let span = terminator.source_info.span;
    match &terminator.kind {
        TerminatorKind::Goto { .. } | TerminatorKind::Return | TerminatorKind::Resume => Ok(()),

        TerminatorKind::Drop { location, .. } => check_place(tcx, location, span, def_id, body),
        TerminatorKind::DropAndReplace { location, value, .. } => {
            check_place(tcx, location, span, def_id, body)?;
            check_operand(tcx, value, span, def_id, body)
        }

        TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. }
            if !feature_allowed(tcx, def_id, sym::const_if_match) =>
        {
            Err((span, "loops and conditional expressions are not stable in const fn".into()))
        }

        TerminatorKind::FalseEdges { .. } => Ok(()),
        TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => {
            check_operand(tcx, discr, span, def_id, body)
        }

        // FIXME(ecstaticmorse): We probably want to allow `Unreachable` unconditionally.
        TerminatorKind::Unreachable if feature_allowed(tcx, def_id, sym::const_if_match) => Ok(()),

        TerminatorKind::Abort | TerminatorKind::Unreachable => {
            Err((span, "const fn with unreachable code is not stable".into()))
        }
        TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
            Err((span, "const fn generators are unstable".into()))
        }

        TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => {
            let fn_ty = func.ty(body, tcx);
            if let ty::FnDef(def_id, _) = fn_ty.kind {
                if !crate::const_eval::is_min_const_fn(tcx, def_id) {
                    return Err((
                        span,
                        format!(
                            "can only call other `const fn` within a `const fn`, \
                             but `{:?}` is not stable as `const fn`",
                            func,
                        )
                        .into(),
                    ));
                }

                check_operand(tcx, func, span, def_id, body)?;

                for arg in args {
                    check_operand(tcx, arg, span, def_id, body)?;
                }
                Ok(())
            } else {
                Err((span, "can only call other const fns within const fn".into()))
            }
        }

        TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => {
            check_operand(tcx, cond, span, def_id, body)
        }

        TerminatorKind::FalseUnwind { .. } if feature_allowed(tcx, def_id, sym::const_loop) => {
            Ok(())
        }

        TerminatorKind::FalseUnwind { .. } => {
            Err((span, "loops are not allowed in const fn".into()))
        }
    }
}
<commit_msg>Expand comment<commit_after>use rustc::mir::*;
use rustc::ty::{self, adjustment::PointerCast, Predicate, Ty, TyCtxt};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use std::borrow::Cow;
use syntax::attr;

type McfResult = Result<(), (Span, Cow<'static, str>)>;

pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -> McfResult {
    let mut current = def_id;
    loop {
        let predicates = tcx.predicates_of(current);
        for (predicate, _) in predicates.predicates {
            match predicate {
                Predicate::RegionOutlives(_)
                | Predicate::TypeOutlives(_)
                | Predicate::WellFormed(_)
                | Predicate::Projection(_)
                | Predicate::ConstEvaluatable(..) => continue,
                Predicate::ObjectSafe(_) => {
                    bug!("object safe predicate on function: {:#?}", predicate)
                }
                Predicate::ClosureKind(..) => {
                    bug!("closure kind predicate on function: {:#?}", predicate)
                }
                Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
                Predicate::Trait(pred) => {
                    if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                        continue;
                    }
                    match pred.skip_binder().self_ty().kind {
                        ty::Param(ref p) => {
                            let generics = tcx.generics_of(current);
                            let def = generics.type_param(p, tcx);
                            let span = tcx.def_span(def.def_id);
                            return Err((
                                span,
                                "trait bounds other than `Sized` \
                                 on const fn parameters are unstable"
                                    .into(),
                            ));
                        }
                        // other kinds of bounds are either tautologies
                        // or cause errors in other passes
                        _ => continue,
                    }
                }
            }
        }
        match predicates.parent {
            Some(parent) => current = parent,
            None => break,
        }
    }

    for local in &body.local_decls {
        check_ty(tcx, local.ty, local.source_info.span, def_id)?;
    }
    // impl trait is gone in MIR, so check the return type manually
    check_ty(
        tcx,
        tcx.fn_sig(def_id).output().skip_binder(),
        body.local_decls.iter().next().unwrap().source_info.span,
        def_id,
    )?;

    for bb in body.basic_blocks() {
        check_terminator(tcx, body, def_id, bb.terminator())?;
        for stmt in &bb.statements {
            check_statement(tcx, body, def_id, stmt)?;
        }
    }
    Ok(())
}

fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult {
    for ty in ty.walk() {
        match ty.kind {
            ty::Ref(_, _, hir::Mutability::Mut) => {
                if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) {
                    return Err((span, "mutable references in const fn are unstable".into()));
                }
            }
            ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
            ty::FnPtr(..) => {
                if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) {
                    return Err((span, "function pointers in const fn are unstable".into()));
                }
            }
            ty::Dynamic(preds, _) => {
                for pred in preds.iter() {
                    match pred.skip_binder() {
                        ty::ExistentialPredicate::AutoTrait(_)
                        | ty::ExistentialPredicate::Projection(_) => {
                            return Err((
                                span,
                                "trait bounds other than `Sized` \
                                 on const fn parameters are unstable"
                                    .into(),
                            ));
                        }
                        ty::ExistentialPredicate::Trait(trait_ref) => {
                            if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
                                return Err((
                                    span,
                                    "trait bounds other than `Sized` \
                                     on const fn parameters are unstable"
                                        .into(),
                                ));
                            }
                        }
                    }
                }
            }
            _ => {}
        }
    }
    Ok(())
}

fn check_rvalue(
    tcx: TyCtxt<'tcx>,
    body: &Body<'tcx>,
    def_id: DefId,
    rvalue: &Rvalue<'tcx>,
    span: Span,
) -> McfResult {
    match rvalue {
        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
            check_operand(tcx, operand, span, def_id, body)
        }
        Rvalue::Len(place)
        | Rvalue::Discriminant(place)
        | Rvalue::Ref(_, _, place)
        | Rvalue::AddressOf(_, place) => check_place(tcx, place, span, def_id, body),
        Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
            use rustc::ty::cast::CastTy;
            let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");
            let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
            match (cast_in, cast_out) {
                (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => {
                    Err((span, "casting pointers to ints is unstable in const fn".into()))
                }
                _ => check_operand(tcx, operand, span, def_id, body),
            }
        }
        Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _)
        | Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, _) => {
            check_operand(tcx, operand, span, def_id, body)
        }
        Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _)
        | Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), _, _)
        | Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), _, _) => {
            Err((span, "function pointer casts are not allowed in const fn".into()))
        }
        Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
            Err((span, "unsizing casts are not allowed in const fn".into()))
        }
        // binops are fine on integers
        Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
            check_operand(tcx, lhs, span, def_id, body)?;
            check_operand(tcx, rhs, span, def_id, body)?;
            let ty = lhs.ty(body, tcx);
            if ty.is_integral() || ty.is_bool() || ty.is_char() {
                Ok(())
            } else {
                Err((span, "only int, `bool` and `char` operations are stable in const fn".into()))
            }
        }
        Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()),
        Rvalue::NullaryOp(NullOp::Box, _) => {
            Err((span, "heap allocations are not allowed in const fn".into()))
        }
        Rvalue::UnaryOp(_, operand) => {
            let ty = operand.ty(body, tcx);
            if ty.is_integral() || ty.is_bool() {
                check_operand(tcx, operand, span, def_id, body)
            } else {
                Err((span, "only int and `bool` operations are stable in const fn".into()))
            }
        }
        Rvalue::Aggregate(_, operands) => {
            for operand in operands {
                check_operand(tcx, operand, span, def_id, body)?;
            }
            Ok(())
        }
    }
}

fn check_statement(
    tcx: TyCtxt<'tcx>,
    body: &Body<'tcx>,
    def_id: DefId,
    statement: &Statement<'tcx>,
) -> McfResult {
    let span = statement.source_info.span;
    match &statement.kind {
        StatementKind::Assign(box (place, rval)) => {
            check_place(tcx, place, span, def_id, body)?;
            check_rvalue(tcx, body, def_id, rval, span)
        }

        StatementKind::FakeRead(FakeReadCause::ForMatchedPlace, _)
            if !feature_allowed(tcx, def_id, sym::const_if_match) =>
        {
            Err((span, "loops and conditional expressions are not stable in const fn".into()))
        }

        StatementKind::FakeRead(_, place) => check_place(tcx, place, span, def_id, body),

        // just an assignment
        StatementKind::SetDiscriminant { place, .. } => check_place(tcx, place, span, def_id, body),

        StatementKind::InlineAsm { .. } => {
            Err((span, "cannot use inline assembly in const fn".into()))
        }

        // These are all NOPs
        StatementKind::StorageLive(_)
        | StatementKind::StorageDead(_)
        | StatementKind::Retag { .. }
        | StatementKind::AscribeUserType(..)
        | StatementKind::Nop => Ok(()),
    }
}

fn check_operand(
    tcx: TyCtxt<'tcx>,
    operand: &Operand<'tcx>,
    span: Span,
    def_id: DefId,
    body: &Body<'tcx>,
) -> McfResult {
    match operand {
        Operand::Move(place) | Operand::Copy(place) => check_place(tcx, place, span, def_id, body),
        Operand::Constant(c) => match c.check_static_ptr(tcx) {
            Some(_) => Err((span, "cannot access `static` items in const fn".into())),
            None => Ok(()),
        },
    }
}

fn check_place(
    tcx: TyCtxt<'tcx>,
    place: &Place<'tcx>,
    span: Span,
    def_id: DefId,
    body: &Body<'tcx>,
) -> McfResult {
    let mut cursor = place.projection.as_ref();
    while let &[ref proj_base @ .., elem] = cursor {
        cursor = proj_base;
        match elem {
            ProjectionElem::Downcast(..) if !feature_allowed(tcx, def_id, sym::const_if_match) => {
                return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
            }
            ProjectionElem::Downcast(_symbol, _variant_index) => {}

            ProjectionElem::Field(..) => {
                let base_ty = Place::ty_from(&place.base, &proj_base, body, tcx).ty;
                if let Some(def) = base_ty.ty_adt_def() {
                    // No union field accesses in `const fn`
                    if def.is_union() {
                        if !feature_allowed(tcx, def_id, sym::const_fn_union) {
                            return Err((span, "accessing union fields is unstable".into()));
                        }
                    }
                }
            }
            ProjectionElem::ConstantIndex { .. }
            | ProjectionElem::Subslice { .. }
            | ProjectionElem::Deref
            | ProjectionElem::Index(_) => {}
        }
    }

    Ok(())
}

/// Returns `true` if the given feature gate is allowed within the function with the given `DefId`.
fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool {
    // All features require that the corresponding gate be enabled,
    // even if the function has `#[allow_internal_unstable(the_gate)]`.
    if !tcx.features().enabled(feature_gate) {
        return false;
    }

    // If this crate is not using stability attributes, or this function is not claiming to be a
    // stable `const fn`, that is all that is required.
    if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) {
        return true;
    }

    // However, we cannot allow stable `const fn`s to use unstable features without an explicit
    // opt-in via `allow_internal_unstable`.
    attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
        .map_or(false, |mut features| features.any(|name| name == feature_gate))
}

fn check_terminator(
    tcx: TyCtxt<'tcx>,
    body: &'a Body<'tcx>,
    def_id: DefId,
    terminator: &Terminator<'tcx>,
) -> McfResult {
    let span = terminator.source_info.span;
    match &terminator.kind {
        TerminatorKind::Goto { .. } | TerminatorKind::Return | TerminatorKind::Resume => Ok(()),

        TerminatorKind::Drop { location, .. } => check_place(tcx, location, span, def_id, body),
        TerminatorKind::DropAndReplace { location, value, .. } => {
            check_place(tcx, location, span, def_id, body)?;
            check_operand(tcx, value, span, def_id, body)
        }

        TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. }
            if !feature_allowed(tcx, def_id, sym::const_if_match) =>
        {
            Err((span, "loops and conditional expressions are not stable in const fn".into()))
        }

        TerminatorKind::FalseEdges { .. } => Ok(()),
        TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => {
            check_operand(tcx, discr, span, def_id, body)
        }

        // FIXME(ecstaticmorse): We probably want to allow `Unreachable` unconditionally.
        TerminatorKind::Unreachable if feature_allowed(tcx, def_id, sym::const_if_match) => Ok(()),

        TerminatorKind::Abort | TerminatorKind::Unreachable => {
            Err((span, "const fn with unreachable code is not stable".into()))
        }
        TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
            Err((span, "const fn generators are unstable".into()))
        }

        TerminatorKind::Call { func, args, from_hir_call: _, destination: _, cleanup: _ } => {
            let fn_ty = func.ty(body, tcx);
            if let ty::FnDef(def_id, _) = fn_ty.kind {
                if !crate::const_eval::is_min_const_fn(tcx, def_id) {
                    return Err((
                        span,
                        format!(
                            "can only call other `const fn` within a `const fn`, \
                             but `{:?}` is not stable as `const fn`",
                            func,
                        )
                        .into(),
                    ));
                }

                check_operand(tcx, func, span, def_id, body)?;

                for arg in args {
                    check_operand(tcx, arg, span, def_id, body)?;
                }
                Ok(())
            } else {
                Err((span, "can only call other const fns within const fn".into()))
            }
        }

        TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => {
            check_operand(tcx, cond, span, def_id, body)
        }

        TerminatorKind::FalseUnwind { .. } if feature_allowed(tcx, def_id, sym::const_loop) => {
            Ok(())
        }

        TerminatorKind::FalseUnwind { .. } => {
            Err((span, "loops are not allowed in const fn".into()))
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use command_buffer::pool::CommandPool;
use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBuffer;
use device::Queue;
use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;

use check_errors;
use vk;
use VulkanObject;
use VulkanPointers;
use SynchronizedVulkanObject;

/// Trait for objects that represent commands ready to be executed by the GPU.
pub unsafe trait CommandBuffer {
    /// Submits the command buffer.
    ///
    /// Note that since submitting has a fixed overhead, you should try, if possible, to submit
    /// multiple command buffers at once instead.
    ///
    /// This is a simple shortcut for creating a `Submit` object.
    #[inline]
    fn submit(self, queue: &Arc<Queue>) -> Submission where Self: Sized {
        Submit::new().add(self).submit(queue)
    }

    /// Type of the pool that was used to allocate the command buffer.
    type Pool: CommandPool;

    /// Iterator that returns the list of semaphores to wait upon before the command buffer is
    /// submitted.
    type SemaphoresWaitIterator: Iterator<Item = (Arc<Semaphore>, PipelineStages)>;

    /// Iterator that returns the list of semaphores to signal after the command buffer has
    /// finished execution.
    type SemaphoresSignalIterator: Iterator<Item = Arc<Semaphore>>;

    /// Returns the inner object.
    fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool>;

    /// Called slightly before the command buffer is submitted. Signals the command buffers that it
    /// is going to be submitted on the given queue. The function must return the list of
    /// semaphores to wait upon and transitions to perform.
    ///
    /// The `fence` parameter is a closure that can be used to pull a fence if required. If a fence
    /// is pulled, it is guaranteed that it will be signaled after the command buffer ends.
    ///
    /// # Safety for the caller
    ///
    /// This function must only be called if there's actually a submission that follows. If a
    /// fence is pulled, then it must eventually be signaled. All the semaphores that are waited
    /// upon must become unsignaled, and all the semaphores that are supposed to be signaled must
    /// become signaled.
    ///
    /// This function is supposed to be called only by vulkano's internals. It is recommended
    /// that you never call it.
    ///
    /// # Safety for the implementation
    ///
    /// The implementation must ensure that the command buffer doesn't get destroyed before the
    /// fence is signaled, or before a fence of a later submission to the same queue is signaled.
    ///
    unsafe fn on_submit<F>(&self, queue_family: u32, queue_within_family: u32, fence: F)
                           -> SubmitInfo<Self::SemaphoresWaitIterator,
                                         Self::SemaphoresSignalIterator>
        where F: FnOnce() -> Arc<Fence>;
}

/// Information about how the submitting function should synchronize the submission.
pub struct SubmitInfo<Swi, Ssi> {
    /// List of semaphores to wait upon before the command buffer starts execution.
    pub semaphores_wait: Swi,
    /// List of semaphores to signal after the command buffer has finished.
    pub semaphores_signal: Ssi,
    /// Pipeline barrier to execute on the queue and immediately before the command buffer.
    /// Ignored if empty.
    pub pre_pipeline_barrier: PipelineBarrierBuilder,
    /// Pipeline barrier to execute on the queue and immediately after the command buffer.
    /// Ignored if empty.
    pub post_pipeline_barrier: PipelineBarrierBuilder,
}

// TODO: docs
// # Leak safety
//
// The `Submission` object can hold borrows of command buffers. In order for it to be safe to leak
// a `Submission`, the borrowed object themselves must be protected by a fence.
#[must_use]
pub struct Submission {
    keep_alive: SmallVec<[Arc<KeepAlive>; 4]>,
}

trait KeepAlive {}
impl<T> KeepAlive for T {}

#[derive(Debug, Copy, Clone)]
pub struct Submit<L> {
    list: L,
}

impl Submit<()> {
    /// Builds an empty submission list.
    #[inline]
    pub fn new() -> Submit<()> {
        Submit { list: () }
    }
}

impl<L> Submit<L> where L: SubmitList {
    /// Adds a command buffer to submit to the list.
    ///
    /// In the Vulkan API, a submission is divided into batches that each contain one or more
    /// command buffers. Vulkano will automatically determine which command buffers can be grouped
    /// into the same batch.
    #[inline]
    pub fn add<C>(self, command_buffer: C) -> Submit<(C, L)> where C: CommandBuffer {
        Submit { list: (command_buffer, self.list) }
    }

    /// Submits the list of command buffers.
    pub fn submit(self, queue: &Arc<Queue>) -> Submission {
        let SubmitListOpaque { fence, wait_semaphores, wait_stages, command_buffers,
                               signal_semaphores, mut submits, keep_alive }
                             = self.list.infos(queue.family().id(), queue.id_within_family());

        // Filling the pointers inside `submits`.
        unsafe {
            debug_assert_eq!(wait_semaphores.len(), wait_stages.len());

            let mut next_wait = 0;
            let mut next_cb = 0;
            let mut next_signal = 0;

            for submit in submits.iter_mut() {
                debug_assert!(submit.waitSemaphoreCount as usize + next_wait as usize <=
                              wait_semaphores.len());
                debug_assert!(submit.commandBufferCount as usize + next_cb as usize <=
                              command_buffers.len());
                debug_assert!(submit.signalSemaphoreCount as usize + next_signal as usize <=
                              signal_semaphores.len());

                submit.pWaitSemaphores = wait_semaphores.as_ptr().offset(next_wait);
                submit.pWaitDstStageMask = wait_stages.as_ptr().offset(next_wait);
                submit.pCommandBuffers = command_buffers.as_ptr().offset(next_cb);
                submit.pSignalSemaphores = signal_semaphores.as_ptr().offset(next_signal);

                next_wait += submit.waitSemaphoreCount as isize;
                next_cb += submit.commandBufferCount as isize;
                next_signal += submit.signalSemaphoreCount as isize;
            }

            debug_assert_eq!(next_wait as usize, wait_semaphores.len());
            debug_assert_eq!(next_wait as usize, wait_stages.len());
            debug_assert_eq!(next_cb as usize, command_buffers.len());
            debug_assert_eq!(next_signal as usize, signal_semaphores.len());
        }

        unsafe {
            let vk = queue.device().pointers();
            let queue = queue.internal_object_guard();
            let fence = fence.as_ref().map(|f| f.internal_object()).unwrap_or(0);
            check_errors(vk.QueueSubmit(*queue, submits.len() as u32, submits.as_ptr(),
                                        fence)).unwrap();        // TODO: handle errors (trickier than it looks)
        }

        Submission {
            keep_alive: keep_alive,
        }
    }
}

/* TODO: All that stuff below is undocumented */

pub struct SubmitListOpaque {
    fence: Option<Arc<Fence>>,
    wait_semaphores: SmallVec<[vk::Semaphore; 16]>,
    wait_stages: SmallVec<[vk::PipelineStageFlags; 16]>,
    command_buffers: SmallVec<[vk::CommandBuffer; 16]>,
    signal_semaphores: SmallVec<[vk::Semaphore; 16]>,
    submits: SmallVec<[vk::SubmitInfo; 8]>,
    keep_alive: SmallVec<[Arc<KeepAlive>; 4]>,
}

pub unsafe trait SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque;
}

unsafe impl SubmitList for () {
    fn infos(self, _: u32, _: u32) -> SubmitListOpaque {
        SubmitListOpaque {
            fence: None,
            wait_semaphores: SmallVec::new(),
            wait_stages: SmallVec::new(),
            command_buffers: SmallVec::new(),
            signal_semaphores: SmallVec::new(),
            submits: SmallVec::new(),
            keep_alive: SmallVec::new(),
        }
    }
}

unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer, R: SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque {
        // TODO: attempt to group multiple submits into one when possible

        let (current, rest) = self;

        let mut infos = rest.infos(queue_family, queue_within_family);
        let device = current.inner().device().clone();
        let current_infos = unsafe { current.on_submit(queue_family, queue_within_family, || {
            if let Some(fence) = infos.fence.as_ref() {
                return fence.clone();
            }

            let new_fence = Fence::new(device);
            infos.fence = Some(new_fence.clone());
            new_fence
        })};

        // TODO: not implemented ; where to store the created command buffers?
        assert!(current_infos.pre_pipeline_barrier.is_empty());
        assert!(current_infos.post_pipeline_barrier.is_empty());

        let mut new_submit = vk::SubmitInfo {
            sType: vk::STRUCTURE_TYPE_SUBMIT_INFO,
            pNext: ptr::null(),
            waitSemaphoreCount: 0,
            pWaitSemaphores: ptr::null(),
            pWaitDstStageMask: ptr::null(),
            commandBufferCount: 1,
            pCommandBuffers: ptr::null(),
            signalSemaphoreCount: 0,
            pSignalSemaphores: ptr::null(),
        };

        for (semaphore, stage) in current_infos.semaphores_wait {
            infos.wait_semaphores.push(semaphore.internal_object());
            infos.wait_stages.push(stage.into());
            infos.keep_alive.push(semaphore);
            new_submit.waitSemaphoreCount += 1;
        }

        for semaphore in current_infos.semaphores_signal {
            infos.signal_semaphores.push(semaphore.internal_object());
            infos.keep_alive.push(semaphore);
            new_submit.signalSemaphoreCount += 1;
        }

        infos.command_buffers.push(current.inner().internal_object());

        infos.submits.push(new_submit);

        infos
    }
}
<commit_msg>Fix the submission object and add docs<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::ptr;
use std::sync::Arc;
use std::time::Duration;
use smallvec::SmallVec;

use command_buffer::pool::CommandPool;
use command_buffer::sys::PipelineBarrierBuilder;
use command_buffer::sys::UnsafeCommandBuffer;
use device::Queue;
use sync::Fence;
use sync::PipelineStages;
use sync::Semaphore;

use check_errors;
use vk;
use VulkanObject;
use VulkanPointers;
use SynchronizedVulkanObject;

/// Trait for objects that represent commands ready to be executed by the GPU.
pub unsafe trait CommandBuffer {
    /// Submits the command buffer.
    ///
    /// Note that since submitting has a fixed overhead, you should try, if possible, to submit
    /// multiple command buffers at once instead.
    ///
    /// This is a simple shortcut for creating a `Submit` object.
    #[inline]
    fn submit(self, queue: &Arc<Queue>) -> Submission where Self: Sized {
        Submit::new().add(self).submit(queue)
    }

    /// Type of the pool that was used to allocate the command buffer.
    type Pool: CommandPool;

    /// Iterator that returns the list of semaphores to wait upon before the command buffer is
    /// submitted.
    type SemaphoresWaitIterator: Iterator<Item = (Arc<Semaphore>, PipelineStages)>;

    /// Iterator that returns the list of semaphores to signal after the command buffer has
    /// finished execution.
    type SemaphoresSignalIterator: Iterator<Item = Arc<Semaphore>>;

    /// Returns the inner object.
    fn inner(&self) -> &UnsafeCommandBuffer<Self::Pool>;

    /// Called slightly before the command buffer is submitted. Signals the command buffers that it
    /// is going to be submitted on the given queue. The function must return the list of
    /// semaphores to wait upon and transitions to perform.
    ///
    /// The `fence` parameter is a closure that can be used to pull a fence if required. If a fence
    /// is pulled, it is guaranteed that it will be signaled after the command buffer ends.
    ///
    /// # Safety for the caller
    ///
    /// This function must only be called if there's actually a submission that follows. If a
    /// fence is pulled, then it must eventually be signaled. All the semaphores that are waited
    /// upon must become unsignaled, and all the semaphores that are supposed to be signaled must
    /// become signaled.
    ///
    /// This function is supposed to be called only by vulkano's internals. It is recommended
    /// that you never call it.
    ///
    /// # Safety for the implementation
    ///
    /// The implementation must ensure that the command buffer doesn't get destroyed before the
    /// fence is signaled, or before a fence of a later submission to the same queue is signaled.
    ///
    unsafe fn on_submit<F>(&self, queue_family: u32, queue_within_family: u32, fence: F)
                           -> SubmitInfo<Self::SemaphoresWaitIterator,
                                         Self::SemaphoresSignalIterator>
        where F: FnOnce() -> Arc<Fence>;
}

/// Information about how the submitting function should synchronize the submission.
pub struct SubmitInfo<Swi, Ssi> {
    /// List of semaphores to wait upon before the command buffer starts execution.
    pub semaphores_wait: Swi,
    /// List of semaphores to signal after the command buffer has finished.
    pub semaphores_signal: Ssi,
    /// Pipeline barrier to execute on the queue and immediately before the command buffer.
    /// Ignored if empty.
    pub pre_pipeline_barrier: PipelineBarrierBuilder,
    /// Pipeline barrier to execute on the queue and immediately after the command buffer.
    /// Ignored if empty.
    pub post_pipeline_barrier: PipelineBarrierBuilder,
}

/// Returned when you submit one or multiple command buffers.
///
/// This object holds the resources that are used by the GPU and that must be kept alive for at
/// least as long as the GPU is executing the submission. Therefore destroying a `Submission`
/// object will block until the GPU is finished executing.
///
/// Whenever you submit a command buffer, you are encouraged to store the returned `Submission`
/// in a long-living container such as a `Vec`. From time to time, you can clean the obsolete
/// objects by checking whether `destroying_would_block()` returns false. For example, if you use
/// a `Vec` you can do `vec.retain(|s| s.destroying_would_block())`.
// TODO: docs
// # Leak safety
//
// The `Submission` object can hold borrows of command buffers. In order for it to be safe to leak
// a `Submission`, the borrowed object themselves must be protected by a fence.
#[must_use]
pub struct Submission {
    fence: Arc<Fence>,      // TODO: make optional
    keep_alive: SmallVec<[Arc<KeepAlive>; 4]>,
}

impl Submission {
    /// Returns `true` if destroying this `Submission` object would block the CPU for some time.
    #[inline]
    pub fn destroying_would_block(&self) -> bool {
        !self.finished()
    }

    /// Returns `true` if the GPU has finished executing this submission.
    #[inline]
    pub fn finished(&self) -> bool {
        self.fence.ready().unwrap_or(false)     // TODO: what to do in case of error?
    }
}

impl Drop for Submission {
    fn drop(&mut self) {
        self.fence.wait(Duration::from_secs(10)).unwrap();      // TODO: handle some errors
    }
}

trait KeepAlive {}
impl<T> KeepAlive for T {}

#[derive(Debug, Copy, Clone)]
pub struct Submit<L> {
    list: L,
}

impl Submit<()> {
    /// Builds an empty submission list.
    #[inline]
    pub fn new() -> Submit<()> {
        Submit { list: () }
    }
}

impl<L> Submit<L> where L: SubmitList {
    /// Adds a command buffer to submit to the list.
    ///
    /// In the Vulkan API, a submission is divided into batches that each contain one or more
    /// command buffers. Vulkano will automatically determine which command buffers can be grouped
    /// into the same batch.
    #[inline]
    pub fn add<C>(self, command_buffer: C) -> Submit<(C, L)> where C: CommandBuffer {
        Submit { list: (command_buffer, self.list) }
    }

    /// Submits the list of command buffers.
    pub fn submit(self, queue: &Arc<Queue>) -> Submission {
        let SubmitListOpaque { fence, wait_semaphores, wait_stages, command_buffers,
                               signal_semaphores, mut submits, keep_alive }
                             = self.list.infos(queue.family().id(), queue.id_within_family());

        // TODO: for now we always create a Fence in order to put it in the submission
        let fence = fence.unwrap_or_else(|| Fence::new(queue.device().clone()));

        // Filling the pointers inside `submits`.
        unsafe {
            debug_assert_eq!(wait_semaphores.len(), wait_stages.len());

            let mut next_wait = 0;
            let mut next_cb = 0;
            let mut next_signal = 0;

            for submit in submits.iter_mut() {
                debug_assert!(submit.waitSemaphoreCount as usize + next_wait as usize <=
                              wait_semaphores.len());
                debug_assert!(submit.commandBufferCount as usize + next_cb as usize <=
                              command_buffers.len());
                debug_assert!(submit.signalSemaphoreCount as usize + next_signal as usize <=
                              signal_semaphores.len());

                submit.pWaitSemaphores = wait_semaphores.as_ptr().offset(next_wait);
                submit.pWaitDstStageMask = wait_stages.as_ptr().offset(next_wait);
                submit.pCommandBuffers = command_buffers.as_ptr().offset(next_cb);
                submit.pSignalSemaphores = signal_semaphores.as_ptr().offset(next_signal);

                next_wait += submit.waitSemaphoreCount as isize;
                next_cb += submit.commandBufferCount as isize;
                next_signal += submit.signalSemaphoreCount as isize;
            }

            debug_assert_eq!(next_wait as usize, wait_semaphores.len());
            debug_assert_eq!(next_wait as usize, wait_stages.len());
            debug_assert_eq!(next_cb as usize, command_buffers.len());
            debug_assert_eq!(next_signal as usize, signal_semaphores.len());
        }

        unsafe {
            let vk = queue.device().pointers();
            let queue = queue.internal_object_guard();
            //let fence = fence.as_ref().map(|f| f.internal_object()).unwrap_or(0);
            let fence = fence.internal_object();
            check_errors(vk.QueueSubmit(*queue, submits.len() as u32, submits.as_ptr(),
                                        fence)).unwrap();        // TODO: handle errors (trickier than it looks)
        }

        Submission {
            keep_alive: keep_alive,
            fence: fence,
        }
    }
}

/* TODO: All that stuff below is undocumented */

pub struct SubmitListOpaque {
    fence: Option<Arc<Fence>>,
    wait_semaphores: SmallVec<[vk::Semaphore; 16]>,
    wait_stages: SmallVec<[vk::PipelineStageFlags; 16]>,
    command_buffers: SmallVec<[vk::CommandBuffer; 16]>,
    signal_semaphores: SmallVec<[vk::Semaphore; 16]>,
    submits: SmallVec<[vk::SubmitInfo; 8]>,
    keep_alive: SmallVec<[Arc<KeepAlive>; 4]>,
}

pub unsafe trait SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque;
}

unsafe impl SubmitList for () {
    fn infos(self, _: u32, _: u32) -> SubmitListOpaque {
        SubmitListOpaque {
            fence: None,
            wait_semaphores: SmallVec::new(),
            wait_stages: SmallVec::new(),
            command_buffers: SmallVec::new(),
            signal_semaphores: SmallVec::new(),
            submits: SmallVec::new(),
            keep_alive: SmallVec::new(),
        }
    }
}

unsafe impl<C, R> SubmitList for (C, R) where C: CommandBuffer, R: SubmitList {
    fn infos(self, queue_family: u32, queue_within_family: u32) -> SubmitListOpaque {
        // TODO: attempt to group multiple submits into one when possible

        let (current, rest) = self;

        let mut infos = rest.infos(queue_family, queue_within_family);
        let device = current.inner().device().clone();
        let current_infos = unsafe { current.on_submit(queue_family, queue_within_family, || {
            if let Some(fence) = infos.fence.as_ref() {
                return fence.clone();
            }

            let new_fence = Fence::new(device);
            infos.fence = Some(new_fence.clone());
            new_fence
        })};

        // TODO: not implemented ; where to store the created command buffers?
        assert!(current_infos.pre_pipeline_barrier.is_empty());
        assert!(current_infos.post_pipeline_barrier.is_empty());

        let mut new_submit = vk::SubmitInfo {
            sType: vk::STRUCTURE_TYPE_SUBMIT_INFO,
            pNext: ptr::null(),
            waitSemaphoreCount: 0,
            pWaitSemaphores: ptr::null(),
            pWaitDstStageMask: ptr::null(),
            commandBufferCount: 1,
            pCommandBuffers: ptr::null(),
            signalSemaphoreCount: 0,
            pSignalSemaphores: ptr::null(),
        };

        for (semaphore, stage) in current_infos.semaphores_wait {
            infos.wait_semaphores.push(semaphore.internal_object());
            infos.wait_stages.push(stage.into());
            infos.keep_alive.push(semaphore);
            new_submit.waitSemaphoreCount += 1;
        }

        for semaphore in current_infos.semaphores_signal {
            infos.signal_semaphores.push(semaphore.internal_object());
            infos.keep_alive.push(semaphore);
            new_submit.signalSemaphoreCount += 1;
        }

        infos.command_buffers.push(current.inner().internal_object());

        infos.submits.push(new_submit);

        infos
    }
}
<|endoftext|>


<commit_before>extern crate serde2;

use serde2::de2;
use serde2::de2::{Deserialize, Deserializer};

#[deriving(Show)]
enum Token {
    Null,
    Int(int),
    //String(String),
    Optiony(bool),
    SeqStart(uint),
    //MapStart(uint),
    End,
}

#[deriving(Show)]
enum Error {
    SyntaxError,
    EndOfStreamError,
}

///////////////////////////////////////////////////////////////////////////////

struct MyDeserializer<Iter> {
    tokens: Iter,
    peeked: ::std::option::Option<Token>,
}

impl<Iter: Iterator<Token>> MyDeserializer<Iter> {
    fn new(tokens: Iter) -> MyDeserializer<Iter> {
        MyDeserializer {
            tokens: tokens,
            peeked: None,
        }
    }

    fn next(&mut self) -> Option<Token> {
        match self.peeked.take() {
            Some(token) => { return Some(token); }
            None => { }
        }

        self.tokens.next()
    }

    fn peek<'a>(&'a mut self) -> Option<&'a Token> {
        match self.peeked {
            Some(_) => { }
            None => { self.peeked = self.tokens.next(); }
        }

        self.peeked.as_ref()
    }
}

impl<Iter: Iterator<Token>> Deserializer<Error> for MyDeserializer<Iter> {
    fn visit<
        R,
        V: de2::Visitor<MyDeserializer<Iter>, R, Error>,
    >(&mut self, visitor: &mut V) -> Result<R, Error> {
        match self.next() {
            Some(Null) => {
                visitor.visit_null(self)
            }
            Some(Int(v)) => {
                visitor.visit_int(self, v)
            }
            /*
            Some(String(v)) => {
                visitor.visit_string(self, v)
            }
            */
            Some(Optiony(is_some)) => {
                visitor.visit_option(self, MyOptionVisitor {
                    is_some: is_some,
                    finished: false,
                })
            }
            Some(SeqStart(len)) => {
                visitor.visit_seq(self, MySeqVisitor { len: len })
            }
            /*
            Some(MapStart(len)) => {
                visitor.visit_map(self, MyMapVisitor { len: len })
            }
            */
            Some(End) => {
                Err(self.syntax_error())
            }
            None => {
                Err(self.end_of_stream_error())
            }
        }
    }

    fn visit_option<
        T: Deserialize<MyDeserializer<Iter>, Error>,
    >(&mut self) -> Result<Option<T>, Error> {
        match self.peek() {
            Some(&Null) => {
                self.next();
                Ok(None)
            }
            Some(&Optiony(true)) => {
                self.next();
                let v = try!(Deserialize::deserialize(self));
                Ok(Some(v))
            }
            Some(&Optiony(false)) => {
                self.next();
                Ok(None)
            }
            _ => {
                let v = try!(Deserialize::deserialize(self));
                Ok(Some(v))
            }
        }
    }

    fn syntax_error(&mut self) -> Error {
        SyntaxError
    }

    fn end_of_stream_error(&mut self) -> Error {
        EndOfStreamError
    }
}

struct MyOptionVisitor {
    is_some: bool,
    finished: bool,
}

impl<
    Iter: Iterator<Token>,
> de2::OptionVisitor<MyDeserializer<Iter>, Error> for MyOptionVisitor {
    fn visit<
        T: Deserialize<MyDeserializer<Iter>, Error>,
    >(&mut self, d: &mut MyDeserializer<Iter>) -> Result<Option<T>, Error> {
        if self.finished {
            Err(d.syntax_error())
        } else {
            self.finished = true;

            if self.is_some {
                let v = try!(Deserialize::deserialize(d));
                Ok(Some(v))
            } else {
                Ok(None)
            }
        }
    }
}

struct MySeqVisitor {
    len: uint,
}

impl<
    Iter: Iterator<Token>,
> de2::SeqVisitor<MyDeserializer<Iter>, Error> for MySeqVisitor {
    fn next<
        T: Deserialize<MyDeserializer<Iter>, Error>
    >(&mut self, d: &mut MyDeserializer<Iter>) -> Option<Result<T, Error>> {
        match d.peek() {
            Some(&End) => {
                d.next();
                None
            }
            Some(_) => {
                self.len -= 1;
                Some(Deserialize::deserialize(d))
            }
            None => {
                Some(Err(d.syntax_error()))
            }
        }
    }

    fn end(&mut self, d: &mut MyDeserializer<Iter>) -> Result<(), Error> {
        match d.next() {
            Some(End) => Ok(()),
            Some(_) => Err(d.syntax_error()),
            None => Err(d.end_of_stream_error()),
        }
    }

    fn size_hint(&self, _d: &mut MyDeserializer<Iter>) -> (uint, Option<uint>) {
        (self.len, Some(self.len))
    }
}

/*
struct MyMapVisitor {
    len: uint,
}

impl<
    Iter: Iterator<Token>,
> Visitor<MyDeserializer<Iter>, ()> for MyMapVisitor {
    fn next(&mut self, d: &mut MyDeserializer<Iter>) -> Option<Result<(K, V), ()>> {
        match d.peek() {
            Some(&End) => {
                d.next();
                None
            }
            Some(_) => {
                self.len -= 1;
                Some(d.visit_map_elt())
            }
            None => {
                Some(Err(d.syntax_error()))
            }
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        (self.len, Some(self.len))
    }
}
*/

///////////////////////////////////////////////////////////////////////////////

mod json {
    //use std::collections::TreeMap;
    use serde2::de2;

    #[deriving(Show)]
    pub enum Value {
        Null,
        //Bool(bool),
        Int(int),
        //String(String),
        List(Vec<Value>),
        //Map(TreeMap<String, Value>),
    }

    impl<
        D: de2::Deserializer<E>,
        E,
    > de2::Deserialize<D, E> for Value {
        fn deserialize(d: &mut D) -> Result<Value, E> {
            struct Visitor;

            impl<
                D: de2::Deserializer<E>,
                E,
            > de2::Visitor<D, Value, E> for Visitor {
                fn visit_null(&mut self, _d: &mut D) -> Result<Value, E> {
                    Ok(Null)
                }

                fn visit_int(&mut self, _d: &mut D, v: int) -> Result<Value, E> {
                    Ok(Int(v))
                }

                /*
                fn visit_string(&mut self, _d: &mut D, v: String) -> Result<Value, E> {
                    Ok(String(v))
                }
                */

                fn visit_option<
                    Visitor: de2::OptionVisitor<D, E>,
                >(&mut self, d: &mut D, mut visitor: Visitor) -> Result<Value, E> {
                    match try!(visitor.visit(d)) {
                        Some(value) => Ok(value),
                        None => Ok(Null),
                    }
                }

                fn visit_seq<
                    Visitor: de2::SeqVisitor<D, E>,
                >(&mut self, d: &mut D, mut visitor: Visitor) -> Result<Value, E> {
                    let (len, _) = visitor.size_hint(d);
                    let mut values = Vec::with_capacity(len);

                    loop {
                        match visitor.next(d) {
                            Some(value) => {
                                values.push(try!(value));
                            }
                            None => {
                                break;
                            }
                        }
                    }

                    Ok(List(values))
                }

                /*
                fn visit_map<
                    Visitor: ::MapVisitor<D, E>,
                >(&mut self, d: &mut D, mut visitor: Visitor) -> Result<Value, E> {
                    let mut values = TreeMap::new();

                    loop {
                        let kv: Option<Result<(String, Value), E>> = visitor.next(d);
                        match kv {
                            Some(Ok((key, value))) => {
                                values.insert(key, value);
                            }
                            Some(Err(err)) => {
                                return Err(err);
                            }
                            None => {
                                break;
                            }
                        }
                    }

                    Ok(Map(values))
                }
                */
            }

            d.visit(&mut Visitor)
        }
    }
}

///////////////////////////////////////////////////////////////////////////////

fn main() {
    let tokens = vec!(
        SeqStart(2),
        Int(1),
        Int(2),
        End,
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<Vec<int>, Error> = Deserialize::deserialize(&mut state);
    println!("vec:          {}", v);

    ////

    let tokens = vec!(
        SeqStart(2),
        Int(1),
        Int(2),
        End,
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<(int, int), Error> = Deserialize::deserialize(&mut state);
    println!("tuple:        {}", v);

    ////

    let tokens = vec!(
        SeqStart(2),
        Int(1),
        Int(2),
        End,
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, Error> = Deserialize::deserialize(&mut state);
    println!("value:        {}", v);

    ////

    let tokens = vec!(
        Optiony(true),
        Int(1),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<Option<int>, Error> = Deserialize::deserialize(&mut state);
    println!("optiony:      {}", v);

    ////

    let tokens = vec!(
        Optiony(false),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<Option<int>, Error> = Deserialize::deserialize(&mut state);
    println!("optiony:      {}", v);

    ////

    let tokens = vec!(
        Optiony(true),
        Int(1),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, Error> = Deserialize::deserialize(&mut state);
    println!("optiony value:{}", v);

    ////

    let tokens = vec!(
        Optiony(false),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, Error> = Deserialize::deserialize(&mut state);
    println!("optiony value:{}", v);

    ////

    let tokens = vec!(
        Int(1),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<Option<int>, Error> = Deserialize::deserialize(&mut state);
    println!("option:       {}", v);

    ////

    let tokens = vec!(
        Null,
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<Option<int>, Error> = Deserialize::deserialize(&mut state);
    println!("option:       {}", v);

    ////

    let tokens = vec!(
        Int(1),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, Error> = Deserialize::deserialize(&mut state);
    println!("option value: {}", v);

    ////

    let tokens = vec!(
        Null,
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, Error> = Deserialize::deserialize(&mut state);
    println!("option value: {}", v);

    /*
    ////

    let tokens = vec!(
        MapStart(2),
        String("a".to_string()),
        Int(1),
        String("b".to_string()),
        Int(2),
        End
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<HashMap<String, int>, ()> = Deserialize::deserialize(&mut state);
    println!("{}", v);

    ////

    let tokens = vec!(
        MapStart(2),
        String("a".to_string()),
        Int(1),
        String("b".to_string()),
        Int(2),
        End
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, ()> = Deserialize::deserialize(&mut state);
    println!("{}", v);
    */
}

/*
use std::collections::TreeMap;
use serde2::{Serialize, GatherTokens};
use serde2::json;

///////////////////////////////////////////////////////////////////////////////

struct Foo {
    x: int,
    y: int,
    z: &'static str,
}

impl<S: serde2::VisitorState<R>, R> serde2::Serialize<S, R> for Foo {
    fn serialize(&self, state: &mut S) -> R {
        state.visit_named_map("Foo", FooSerialize {
            value: self,
            state: 0,
        })
    }
}

struct FooSerialize<'a> {
    value: &'a Foo,
    state: uint,
}

impl<'a, S: serde2::VisitorState<R>, R> serde2::Visitor<S, R> for FooSerialize<'a> {
    fn visit(&mut self, state: &mut S) -> Option<R> {
        match self.state {
            0 => {
                self.state += 1;
                Some(state.visit_map_elt(true, "x", &self.value.x))
            }
            1 => {
                self.state += 1;
                Some(state.visit_map_elt(false, "y", &self.value.y))
            }
            2 => {
                self.state += 1;
                Some(state.visit_map_elt(false, "z", &self.value.z))
            }
            _ => {
                None
            }
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        let size = 3 - self.state;
        (size, Some(size))
    }
}

///////////////////////////////////////////////////////////////////////////////

fn main() {
    let value = 5i;

    let mut s = GatherTokens::new();
    value.serialize(&mut s);
    println!("tokens: {}", s.unwrap());

    println!("json:   {}", json::to_string(&value).unwrap().unwrap());
    println!("");

    ////

    let value = vec!(1i, 2, 3);

    let mut s = GatherTokens::new();
    value.serialize(&mut s);
    println!("tokens: {}", s.unwrap());

    println!("json:   {}", json::to_string(&value).unwrap().unwrap());
    println!("");

    ////

    let mut value = TreeMap::new();
    value.insert("a", 1i);
    value.insert("b", 2);
    value.insert("c", 3);

    let mut s = GatherTokens::new();
    value.serialize(&mut s);
    println!("tokens: {}", s.unwrap());

    println!("json:   {}", json::to_string(&value).unwrap().unwrap());
    println!("");

    ////

    /*
    println!("{}", to_format_vec(&5i));
    println!("{}", to_format_string(&5i));
    */

    let value = Foo { x: 1, y: 2, z: "abc" };

    let mut s = GatherTokens::new();
    value.serialize(&mut s);
    println!("tokens: {}", s.unwrap());

    println!("json:   {}", json::to_string(&value).unwrap().unwrap());
    println!("");

    ////

    let value = (1i, "abc");

    let mut s = GatherTokens::new();
    value.serialize(&mut s);
    println!("tokens: {}", s.unwrap());

    println!("json:   {}", json::to_string(&value).unwrap().unwrap());
    println!("");
}
*/
<commit_msg>Minor cleanup<commit_after>extern crate serde2;

use std::string;
use std::option;

use serde2::de2;
use serde2::de2::{Deserialize, Deserializer};

#[deriving(Show)]
enum Token {
    Null,
    Int(int),
    String(string::String),
    Option(bool),
    SeqStart(uint),
    //MapStart(uint),
    End,
}

#[deriving(Show)]
enum Error {
    SyntaxError,
    EndOfStreamError,
}

///////////////////////////////////////////////////////////////////////////////

struct MyDeserializer<Iter> {
    tokens: Iter,
    peeked: option::Option<Token>,
}

impl<Iter: Iterator<Token>> MyDeserializer<Iter> {
    fn new(tokens: Iter) -> MyDeserializer<Iter> {
        MyDeserializer {
            tokens: tokens,
            peeked: None,
        }
    }

    fn next(&mut self) -> option::Option<Token> {
        match self.peeked.take() {
            Some(token) => { return Some(token); }
            None => { }
        }

        self.tokens.next()
    }

    fn peek<'a>(&'a mut self) -> option::Option<&'a Token> {
        match self.peeked {
            Some(_) => { }
            None => { self.peeked = self.tokens.next(); }
        }

        self.peeked.as_ref()
    }
}

impl<Iter: Iterator<Token>> Deserializer<Error> for MyDeserializer<Iter> {
    fn visit<
        R,
        V: de2::Visitor<MyDeserializer<Iter>, R, Error>,
    >(&mut self, visitor: &mut V) -> Result<R, Error> {
        match self.next() {
            Some(Null) => {
                visitor.visit_null(self)
            }
            Some(Int(v)) => {
                visitor.visit_int(self, v)
            }
            Some(String(v)) => {
                visitor.visit_string(self, v)
            }
            Some(Option(is_some)) => {
                visitor.visit_option(self, MyOptionVisitor {
                    is_some: is_some,
                    finished: false,
                })
            }
            Some(SeqStart(len)) => {
                visitor.visit_seq(self, MySeqVisitor { len: len })
            }
            /*
            Some(MapStart(len)) => {
                visitor.visit_map(self, MyMapVisitor { len: len })
            }
            */
            Some(End) => {
                Err(self.syntax_error())
            }
            None => {
                Err(self.end_of_stream_error())
            }
        }
    }

    fn visit_option<
        T: Deserialize<MyDeserializer<Iter>, Error>,
    >(&mut self) -> Result<option::Option<T>, Error> {
        match self.peek() {
            Some(&Null) => {
                self.next();
                Ok(None)
            }
            Some(&Option(true)) => {
                self.next();
                let v = try!(Deserialize::deserialize(self));
                Ok(Some(v))
            }
            Some(&Option(false)) => {
                self.next();
                Ok(None)
            }
            _ => {
                let v = try!(Deserialize::deserialize(self));
                Ok(Some(v))
            }
        }
    }

    fn syntax_error(&mut self) -> Error {
        SyntaxError
    }

    fn end_of_stream_error(&mut self) -> Error {
        EndOfStreamError
    }
}

struct MyOptionVisitor {
    is_some: bool,
    finished: bool,
}

impl<
    Iter: Iterator<Token>,
> de2::OptionVisitor<MyDeserializer<Iter>, Error> for MyOptionVisitor {
    fn visit<
        T: Deserialize<MyDeserializer<Iter>, Error>,
    >(&mut self, d: &mut MyDeserializer<Iter>) -> Result<option::Option<T>, Error> {
        if self.finished {
            Err(d.syntax_error())
        } else {
            self.finished = true;

            if self.is_some {
                let v = try!(Deserialize::deserialize(d));
                Ok(Some(v))
            } else {
                Ok(None)
            }
        }
    }
}

struct MySeqVisitor {
    len: uint,
}

impl<
    Iter: Iterator<Token>,
> de2::SeqVisitor<MyDeserializer<Iter>, Error> for MySeqVisitor {
    fn next<
        T: Deserialize<MyDeserializer<Iter>, Error>
    >(&mut self, d: &mut MyDeserializer<Iter>) -> option::Option<Result<T, Error>> {
        match d.peek() {
            Some(&End) => {
                d.next();
                None
            }
            Some(_) => {
                self.len -= 1;
                Some(Deserialize::deserialize(d))
            }
            None => {
                Some(Err(d.syntax_error()))
            }
        }
    }

    fn end(&mut self, d: &mut MyDeserializer<Iter>) -> Result<(), Error> {
        match d.next() {
            Some(End) => Ok(()),
            Some(_) => Err(d.syntax_error()),
            None => Err(d.end_of_stream_error()),
        }
    }

    fn size_hint(&self, _d: &mut MyDeserializer<Iter>) -> (uint, option::Option<uint>) {
        (self.len, Some(self.len))
    }
}

/*
struct MyMapVisitor {
    len: uint,
}

impl<
    Iter: Iterator<Token>,
> Visitor<MyDeserializer<Iter>, ()> for MyMapVisitor {
    fn next(&mut self, d: &mut MyDeserializer<Iter>) -> Option<Result<(K, V), ()>> {
        match d.peek() {
            Some(&End) => {
                d.next();
                None
            }
            Some(_) => {
                self.len -= 1;
                Some(d.visit_map_elt())
            }
            None => {
                Some(Err(d.syntax_error()))
            }
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        (self.len, Some(self.len))
    }
}
*/

///////////////////////////////////////////////////////////////////////////////

mod json {
    //use std::collections::TreeMap;
    use serde2::de2;

    #[deriving(Show)]
    pub enum Value {
        Null,
        //Bool(bool),
        Int(int),
        //String(String),
        List(Vec<Value>),
        //Map(TreeMap<String, Value>),
    }

    impl<
        D: de2::Deserializer<E>,
        E,
    > de2::Deserialize<D, E> for Value {
        fn deserialize(d: &mut D) -> Result<Value, E> {
            struct Visitor;

            impl<
                D: de2::Deserializer<E>,
                E,
            > de2::Visitor<D, Value, E> for Visitor {
                fn visit_null(&mut self, _d: &mut D) -> Result<Value, E> {
                    Ok(Null)
                }

                fn visit_int(&mut self, _d: &mut D, v: int) -> Result<Value, E> {
                    Ok(Int(v))
                }

                /*
                fn visit_string(&mut self, _d: &mut D, v: String) -> Result<Value, E> {
                    Ok(String(v))
                }
                */

                fn visit_option<
                    Visitor: de2::OptionVisitor<D, E>,
                >(&mut self, d: &mut D, mut visitor: Visitor) -> Result<Value, E> {
                    match try!(visitor.visit(d)) {
                        Some(value) => Ok(value),
                        None => Ok(Null),
                    }
                }

                fn visit_seq<
                    Visitor: de2::SeqVisitor<D, E>,
                >(&mut self, d: &mut D, mut visitor: Visitor) -> Result<Value, E> {
                    let (len, _) = visitor.size_hint(d);
                    let mut values = Vec::with_capacity(len);

                    loop {
                        match visitor.next(d) {
                            Some(value) => {
                                values.push(try!(value));
                            }
                            None => {
                                break;
                            }
                        }
                    }

                    Ok(List(values))
                }

                /*
                fn visit_map<
                    Visitor: ::MapVisitor<D, E>,
                >(&mut self, d: &mut D, mut visitor: Visitor) -> Result<Value, E> {
                    let mut values = TreeMap::new();

                    loop {
                        let kv: Option<Result<(String, Value), E>> = visitor.next(d);
                        match kv {
                            Some(Ok((key, value))) => {
                                values.insert(key, value);
                            }
                            Some(Err(err)) => {
                                return Err(err);
                            }
                            None => {
                                break;
                            }
                        }
                    }

                    Ok(Map(values))
                }
                */
            }

            d.visit(&mut Visitor)
        }
    }
}

///////////////////////////////////////////////////////////////////////////////

fn main() {
    let tokens = vec!(
        SeqStart(2),
        Int(1),
        Int(2),
        End,
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<Vec<int>, Error> = Deserialize::deserialize(&mut state);
    println!("vec:           {}", v);

    ////

    let tokens = vec!(
        SeqStart(2),
        Int(1),
        Int(2),
        End,
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<(int, int), Error> = Deserialize::deserialize(&mut state);
    println!("tuple:         {}", v);

    ////

    let tokens = vec!(
        SeqStart(2),
        Int(1),
        Int(2),
        End,
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, Error> = Deserialize::deserialize(&mut state);
    println!("value:         {}", v);

    ////

    let tokens = vec!(
        Option(true),
        Int(1),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<option::Option<int>, Error> = Deserialize::deserialize(&mut state);
    println!("optiony:       {}", v);

    ////

    let tokens = vec!(
        Option(false),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<option::Option<int>, Error> = Deserialize::deserialize(&mut state);
    println!("optiony:       {}", v);

    ////

    let tokens = vec!(
        Option(true),
        Int(1),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, Error> = Deserialize::deserialize(&mut state);
    println!("optiony value: {}", v);

    ////

    let tokens = vec!(
        Option(false),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, Error> = Deserialize::deserialize(&mut state);
    println!("optiony value: {}", v);

    ////

    let tokens = vec!(
        Int(1),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<option::Option<int>, Error> = Deserialize::deserialize(&mut state);
    println!("option:        {}", v);

    ////

    let tokens = vec!(
        Null,
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<option::Option<int>, Error> = Deserialize::deserialize(&mut state);
    println!("option:        {}", v);

    ////

    let tokens = vec!(
        Int(1),
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, Error> = Deserialize::deserialize(&mut state);
    println!("option value:  {}", v);

    ////

    let tokens = vec!(
        Null,
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, Error> = Deserialize::deserialize(&mut state);
    println!("option value:  {}", v);

    /*
    ////

    let tokens = vec!(
        MapStart(2),
        String("a".to_string()),
        Int(1),
        String("b".to_string()),
        Int(2),
        End
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<HashMap<String, int>, ()> = Deserialize::deserialize(&mut state);
    println!("{}", v);

    ////

    let tokens = vec!(
        MapStart(2),
        String("a".to_string()),
        Int(1),
        String("b".to_string()),
        Int(2),
        End
    );
    let mut state = MyDeserializer::new(tokens.into_iter());

    let v: Result<json::Value, ()> = Deserialize::deserialize(&mut state);
    println!("{}", v);
    */
}

/*
use std::collections::TreeMap;
use serde2::{Serialize, GatherTokens};
use serde2::json;

///////////////////////////////////////////////////////////////////////////////

struct Foo {
    x: int,
    y: int,
    z: &'static str,
}

impl<S: serde2::VisitorState<R>, R> serde2::Serialize<S, R> for Foo {
    fn serialize(&self, state: &mut S) -> R {
        state.visit_named_map("Foo", FooSerialize {
            value: self,
            state: 0,
        })
    }
}

struct FooSerialize<'a> {
    value: &'a Foo,
    state: uint,
}

impl<'a, S: serde2::VisitorState<R>, R> serde2::Visitor<S, R> for FooSerialize<'a> {
    fn visit(&mut self, state: &mut S) -> Option<R> {
        match self.state {
            0 => {
                self.state += 1;
                Some(state.visit_map_elt(true, "x", &self.value.x))
            }
            1 => {
                self.state += 1;
                Some(state.visit_map_elt(false, "y", &self.value.y))
            }
            2 => {
                self.state += 1;
                Some(state.visit_map_elt(false, "z", &self.value.z))
            }
            _ => {
                None
            }
        }
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        let size = 3 - self.state;
        (size, Some(size))
    }
}

///////////////////////////////////////////////////////////////////////////////

fn main() {
    let value = 5i;

    let mut s = GatherTokens::new();
    value.serialize(&mut s);
    println!("tokens: {}", s.unwrap());

    println!("json:   {}", json::to_string(&value).unwrap().unwrap());
    println!("");

    ////

    let value = vec!(1i, 2, 3);

    let mut s = GatherTokens::new();
    value.serialize(&mut s);
    println!("tokens: {}", s.unwrap());

    println!("json:   {}", json::to_string(&value).unwrap().unwrap());
    println!("");

    ////

    let mut value = TreeMap::new();
    value.insert("a", 1i);
    value.insert("b", 2);
    value.insert("c", 3);

    let mut s = GatherTokens::new();
    value.serialize(&mut s);
    println!("tokens: {}", s.unwrap());

    println!("json:   {}", json::to_string(&value).unwrap().unwrap());
    println!("");

    ////

    /*
    println!("{}", to_format_vec(&5i));
    println!("{}", to_format_string(&5i));
    */

    let value = Foo { x: 1, y: 2, z: "abc" };

    let mut s = GatherTokens::new();
    value.serialize(&mut s);
    println!("tokens: {}", s.unwrap());

    println!("json:   {}", json::to_string(&value).unwrap().unwrap());
    println!("");

    ////

    let value = (1i, "abc");

    let mut s = GatherTokens::new();
    value.serialize(&mut s);
    println!("tokens: {}", s.unwrap());

    println!("json:   {}", json::to_string(&value).unwrap().unwrap());
    println!("");
}
*/
<|endoftext|>


<commit_before>extern crate sled;
extern crate libc;

use std::fs;
use std::thread;
use std::time::Duration;

const CYCLE: usize = 16; // 65536;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        None => return (0, 0),
        Some((_k, v)) => slice_to_u32(&*v),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for (mut k, v) in iter {
        if v == highest_vec {
            contiguous += 1;
        } else {
            k.reverse();
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    let lowest_vec = u32_to_vec(lowest);

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for (mut k, v) in tree.scan(&*low_beginning) {
        if v != lowest_vec {
            k.reverse();
        }
        assert_eq!(
            v,
            lowest_vec,
            "expected key {} to have value {}, instead it had value {}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v)
        );
    }

    (contiguous, highest)
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; 4] = unsafe { std::mem::transmute(u) };
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; 4];
    buf.copy_from_slice(b);

    unsafe { std::mem::transmute(buf) }
}

fn run(config: sled::FinalConfig) {
    let tree = config.tree();

    // flush to ensure the initial root is stable.
    tree.flush();

    let (key, highest) = verify(&tree);

    thread::spawn(|| {
        thread::sleep(Duration::from_millis(100));
        unsafe {
            libc::raise(9);
        }
    });

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let mut key = u32_to_vec((hu % CYCLE) as u32);
        key.reverse();
        let value = u32_to_vec((hu / CYCLE) as u32);
        tree.set(key, value);
    }
}

fn run_without_snapshot() {
    let config = sled::Config::default()
        .io_bufs(2)
        .blink_fanout(15)
        .page_consolidation_threshold(10)
        .cache_fixup_threshold(1)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(100_000) // 1<<16 is 65k but might cause stalling
        .path("test_crashes".to_string())
        .snapshot_after_ops(1 << 56)
        .build();

    run(config);
}

fn run_with_snapshot() {
    let config = sled::Config::default()
        .io_bufs(2)
        .blink_fanout(15)
        .page_consolidation_threshold(10)
        .cache_fixup_threshold(1)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(100_000) // 1<<16 is 65k but might cause stalling
        .path("test_crashes_with_snapshot".to_string())
        .snapshot_after_ops(1 << 10)
        .build();

    run(config);
}

#[test]
fn test_crash_recovery_with_runtime_snapshot() {
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup_with_snapshots();
}

#[test]
fn test_crash_recovery_no_runtime_snapshot() {
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup();
}

fn cleanup_with_snapshots() {
    let _res = fs::remove_file("test_crashes_with_snapshot.db");
    let _res = fs::remove_file("test_crashes_with_snapshot.conf");
    for dir_entry in fs::read_dir(".").unwrap() {
        if let Ok(de) = dir_entry {
            let path_buf = de.path();
            let path = path_buf.as_path();
            let path_str = path.to_str().unwrap();
            if path_str.starts_with("./test_crashes_with_snapshot.snap.") {
                let _res = fs::remove_file(path);
            }
        }
    }
}

fn cleanup() {
    let _res = fs::remove_file("test_crashes.db");
    let _res = fs::remove_file("test_crashes.conf");
    for dir_entry in fs::read_dir(".").unwrap() {
        if let Ok(de) = dir_entry {
            let path_buf = de.path();
            let path = path_buf.as_path();
            let path_str = path.to_str().unwrap();
            if path_str.starts_with("./test_crashes.snap.") {
                let _res = fs::remove_file(path);
            }
        }
    }
}
<commit_msg>reduce chances of interfering cache in crash test<commit_after>extern crate sled;
extern crate libc;

use std::fs;
use std::thread;
use std::time::Duration;

const CYCLE: usize = 16; // 65536;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        None => return (0, 0),
        Some((_k, v)) => slice_to_u32(&*v),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for (mut k, v) in iter {
        if v == highest_vec {
            contiguous += 1;
        } else {
            k.reverse();
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    let lowest_vec = u32_to_vec(lowest);

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for (mut k, v) in tree.scan(&*low_beginning) {
        if v != lowest_vec {
            k.reverse();
        }
        assert_eq!(
            v,
            lowest_vec,
            "expected key {} to have value {}, instead it had value {}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v)
        );
    }

    (contiguous, highest)
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; 4] = unsafe { std::mem::transmute(u) };
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; 4];
    buf.copy_from_slice(b);

    unsafe { std::mem::transmute(buf) }
}

fn run(config: sled::FinalConfig) {
    let tree = config.tree();

    // flush to ensure the initial root is stable.
    tree.flush();

    let (key, highest) = verify(&tree);

    thread::spawn(|| {
        thread::sleep(Duration::from_millis(100));
        unsafe {
            libc::raise(9);
        }
    });

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let mut key = u32_to_vec((hu % CYCLE) as u32);
        key.reverse();
        let value = u32_to_vec((hu / CYCLE) as u32);
        tree.set(key, value);
    }
}

fn run_without_snapshot() {
    let config = sled::Config::default()
        .io_bufs(2)
        .blink_fanout(15)
        .page_consolidation_threshold(10)
        .cache_fixup_threshold(1)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(100_000) // 1<<16 is 65k but might cause stalling
        .path("test_crashes".to_string())
        .snapshot_after_ops(1 << 56)
        .build();

    run(config);
}

fn run_with_snapshot() {
    let config = sled::Config::default()
        .io_bufs(2)
        .blink_fanout(15)
        .page_consolidation_threshold(10)
        .cache_fixup_threshold(1)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(100_000) // 1<<16 is 65k but might cause stalling
        .path("test_crashes_with_snapshot".to_string())
        .snapshot_after_ops(1 << 10)
        .build();

    run(config);
}

#[test]
fn test_crash_recovery_with_runtime_snapshot() {
    cleanup_with_snapshots();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup_with_snapshots();
}

#[test]
fn test_crash_recovery_no_runtime_snapshot() {
    cleanup();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup();
}

fn cleanup_with_snapshots() {
    let _res = fs::remove_file("test_crashes_with_snapshot.db");
    let _res = fs::remove_file("test_crashes_with_snapshot.conf");
    for dir_entry in fs::read_dir(".").unwrap() {
        if let Ok(de) = dir_entry {
            let path_buf = de.path();
            let path = path_buf.as_path();
            let path_str = path.to_str().unwrap();
            if path_str.starts_with("./test_crashes_with_snapshot.snap.") {
                let _res = fs::remove_file(path);
            }
        }
    }
}

fn cleanup() {
    let _res = fs::remove_file("test_crashes.db");
    let _res = fs::remove_file("test_crashes.conf");
    for dir_entry in fs::read_dir(".").unwrap() {
        if let Ok(de) = dir_entry {
            let path_buf = de.path();
            let path = path_buf.as_path();
            let path_str = path.to_str().unwrap();
            if path_str.starts_with("./test_crashes.snap.") {
                let _res = fs::remove_file(path);
            }
        }
    }
}
<|endoftext|>