<commit_before>use std::collections::HashMap;

#[derive(PartialEq,Eq,Debug,Hash,Clone)]
pub enum BasicValue {
    Byte(u8),
    Boolean(bool),
    Int16(i16),
    Uint16(u16),
    Int32(i32),
    Uint32(u32),
    Int64(i64),
    Uint64(u64),
    String(String),
    ObjectPath(Path),
    Signature(Signature),
}

#[derive(Clone,PartialEq,Eq,Debug,Hash)]
pub struct Path(pub String);

#[derive(Clone,PartialEq,Eq,Debug,Hash)]
pub struct Signature(pub String);

#[derive(PartialEq,Debug,Clone)]
pub struct Struct {
    pub objects: Vec<Value>,
    pub signature: Signature
}

#[derive(PartialEq,Debug,Clone)]
pub struct Variant {
    pub object: Box<Value>,
    pub signature: Signature
}

impl Variant {
    pub fn new (v: Value, s: &str) -> Variant {
        Variant {
            object: Box::new(v),
            signature: Signature(s.to_string())
        }
    }
}

pub type Dictionary = HashMap<BasicValue,Value>;

#[derive(PartialEq,Debug,Clone)]
pub enum Value {
    BasicValue(BasicValue),
    Double(f64),
    Array(Vec<Value>),
    Variant(Variant),
    Struct(Struct),
    Dictionary(Dictionary)
}

impl<'a> From<&'a Value> for u8 {
    fn from(v: &'a Value) -> u8 {
        match v {
            &Value::BasicValue(BasicValue::Byte(x)) => x,
            _ => panic!("Not a byte")
        }
    }
}

impl<'a> From<&'a Value> for i16 {
    fn from(v: &'a Value) -> i16 {
        match v {
            &Value::BasicValue(BasicValue::Int16(x)) => x,
            _ => panic!("Not an Int16")
        }
    }
}

impl<'a> From<&'a Value> for i32 {
    fn from(v: &'a Value) -> i32 {
        match v {
            &Value::BasicValue(BasicValue::Int32(x)) => x,
            _ => panic!("Not an Int32")
        }
    }
}

impl<'a> From<&'a Value> for i64 {
    fn from(v: &'a Value) -> i64 {
        match v {
            &Value::BasicValue(BasicValue::Int64(x)) => x,
            _ => panic!("Not an Int64")
        }
    }
}

impl<'a> From<&'a Value> for u16 {
    fn from(v: &'a Value) -> u16 {
        match v {
            &Value::BasicValue(BasicValue::Uint16(x)) => x,
            _ => panic!("Not a Uint16")
        }
    }
}

impl<'a> From<&'a Value> for u32 {
    fn from(v: &'a Value) -> u32 {
        match v {
            &Value::BasicValue(BasicValue::Uint32(x)) => x,
            _ => panic!("Not a Uint32")
        }
    }
}

impl<'a> From<&'a Value> for u64 {
    fn from(v: &'a Value) -> u64 {
        match v {
            &Value::BasicValue(BasicValue::Uint64(x)) => x,
            _ => panic!("Not a Uint32")
        }
    }
}

impl<'a> From<&'a Value> for String {
    fn from(v: &'a Value) -> String {
        match v {
            &Value::BasicValue(BasicValue::String(ref x)) => x.to_string(),
            &Value::BasicValue(BasicValue::ObjectPath(Path(ref x))) => x.to_string(),
            &Value::BasicValue(BasicValue::Signature(Signature(ref x))) => x.to_string(),
            _ => panic!("Not a string type")
        }
    }
}

#[test]
fn test_from () {
    let x = Value::from(12);
    assert_eq!(x, Value::BasicValue(BasicValue::Int32(12)));
    let y = Value::from("foobar");
    assert_eq!(y, Value::BasicValue(BasicValue::String("foobar".to_string())));
}
<commit_msg>types.rs: remove redundant From implementations<commit_after>use std::collections::HashMap;

#[derive(PartialEq,Eq,Debug,Hash,Clone)]
pub enum BasicValue {
    Byte(u8),
    Boolean(bool),
    Int16(i16),
    Uint16(u16),
    Int32(i32),
    Uint32(u32),
    Int64(i64),
    Uint64(u64),
    String(String),
    ObjectPath(Path),
    Signature(Signature),
}

#[derive(Clone,PartialEq,Eq,Debug,Hash)]
pub struct Path(pub String);

#[derive(Clone,PartialEq,Eq,Debug,Hash)]
pub struct Signature(pub String);

#[derive(PartialEq,Debug,Clone)]
pub struct Struct {
    pub objects: Vec<Value>,
    pub signature: Signature
}

#[derive(PartialEq,Debug,Clone)]
pub struct Variant {
    pub object: Box<Value>,
    pub signature: Signature
}

impl Variant {
    pub fn new (v: Value, s: &str) -> Variant {
        Variant {
            object: Box::new(v),
            signature: Signature(s.to_string())
        }
    }
}

pub type Dictionary = HashMap<BasicValue,Value>;

#[derive(PartialEq,Debug,Clone)]
pub enum Value {
    BasicValue(BasicValue),
    Double(f64),
    Array(Vec<Value>),
    Variant(Variant),
    Struct(Struct),
    Dictionary(Dictionary)
}

#[test]
fn test_from () {
    let x = Value::from(12);
    assert_eq!(x, Value::BasicValue(BasicValue::Int32(12)));
    let y = Value::from("foobar");
    assert_eq!(y, Value::BasicValue(BasicValue::String("foobar".to_string())));
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use syntax::ast;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::ptr::P;
use rustc::middle::ty;
use syntax::codemap::ExpnInfo;

use utils::{in_macro, snippet, span_lint, span_help_and_lint, in_external_macro};

/// Handles all the linting of funky types
#[allow(missing_copy_implementations)]
pub struct TypePass;

declare_lint!(pub BOX_VEC, Warn,
              "usage of `Box<Vec<T>>`, vector elements are already on the heap");
declare_lint!(pub LINKEDLIST, Warn,
              "usage of LinkedList, usually a vector is faster, or a more specialized data \
               structure like a RingBuf");

/// Matches a type with a provided string, and returns its type parameters if successful
pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
    match ty.node {
        TyPath(_, Path {segments: ref seg, ..}) => {
            // So ast::Path isn't the full path, just the tokens that were provided.
            // I could muck around with the maps and find the full path
            // however the more efficient way is to simply reverse the iterators and zip them
            // which will compare them in reverse until one of them runs out of segments
            if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.name == b) {
                match seg[..].last() {
                    Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => {
                        Some(&a.types[..])
                    }
                    _ => None
                }
            } else {
                None
            }
        },
        _ => None
    }
}

#[allow(unused_imports)]
impl LintPass for TypePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(BOX_VEC, LINKEDLIST)
    }

    fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) {
        {
            // In case stuff gets moved around
            use std::boxed::Box;
            use std::vec::Vec;
        }
        match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first())
          .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"]))
          .map(|_| {
            span_help_and_lint(cx, BOX_VEC, ty.span,
                              "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?",
                              "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation");
          });
        {
            // In case stuff gets moved around
            use collections::linked_list::LinkedList as DL1;
            use std::collections::linked_list::LinkedList as DL2;
        }
        let dlists = [vec!["std","collections","linked_list","LinkedList"],
                      vec!["collections","linked_list","LinkedList"]];
        for path in &dlists {
            if match_ty_unwrap(ty, &path[..]).is_some() {
                span_help_and_lint(cx, LINKEDLIST, ty.span,
                                   "I see you're using a LinkedList! Perhaps you meant some other data structure?",
                                   "a RingBuf might work");
                return;
            }
        }
    }
}

#[allow(missing_copy_implementations)]
pub struct LetPass;

declare_lint!(pub LET_UNIT_VALUE, Warn,
              "creating a let binding to a value of unit type, which usually can't be used afterwards");

fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) {
    if in_macro(cx, info) { return; }
    if let DeclLocal(ref local) = decl.node {
        let bindtype = &cx.tcx.pat_ty(&*local.pat).sty;
        if *bindtype == ty::TyTuple(vec![]) {
            span_lint(cx, LET_UNIT_VALUE, decl.span, &format!(
                "this let-binding has unit value. Consider omitting `let {} =`",
                snippet(cx, local.pat.span, "..")));
        }
    }
}

impl LintPass for LetPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(LET_UNIT_VALUE)
    }

    fn check_decl(&mut self, cx: &Context, decl: &Decl) {
        cx.sess().codemap().with_expn_info(
            decl.span.expn_id,
            |info| check_let_unit(cx, decl, info));
    }
}

declare_lint!(pub UNIT_CMP, Warn,
              "comparing unit values (which is always `true` or `false`, respectively)");

#[allow(missing_copy_implementations)]
pub struct UnitCmp;

impl LintPass for UnitCmp {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNIT_CMP)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprBinary(ref cmp, ref left, _) = expr.node {
            let op = cmp.node;
            let sty = &cx.tcx.expr_ty(left).sty;
            if *sty == ty::TyTuple(vec![]) && is_comparison_binop(op) {
                let result = match op {
                    BiEq | BiLe | BiGe => "true",
                    _ => "false"
                };
                span_lint(cx, UNIT_CMP, expr.span, &format!(
                    "{}-comparison of unit values detected. This will always be {}",
                    binop_to_string(op), result));
            }
        }
    }
}

pub struct CastPass;

declare_lint!(pub CAST_PRECISION_LOSS, Allow,
              "casts that cause loss of precision, e.g `x as f32` where `x: u64`");
declare_lint!(pub CAST_SIGN_LOSS, Allow,
              "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`");
declare_lint!(pub CAST_POSSIBLE_OVERFLOW, Allow,
              "casts that may cause overflow, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`");

impl LintPass for CastPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(CAST_PRECISION_LOSS,
                    CAST_SIGN_LOSS,
                    CAST_POSSIBLE_OVERFLOW)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprCast(ref ex, _) = expr.node {
            let (cast_from, cast_to) = (cx.tcx.expr_ty(&*ex), cx.tcx.expr_ty(expr));
            if cast_from.is_numeric() && !in_external_macro(cx, expr.span) {
                match (cast_from.is_integral(), cast_to.is_integral()) {
                    (true, false)  => {
                        match (&cast_from.sty, &cast_to.sty) {
                            (&ty::TypeVariants::TyInt(i), &ty::TypeVariants::TyFloat(f)) => {
                                match (i, f) {
                                    (ast::IntTy::TyI32, ast::FloatTy::TyF32) |
                                    (ast::IntTy::TyI64, ast::FloatTy::TyF32) |
                                    (ast::IntTy::TyI64, ast::FloatTy::TyF64) => {
                                        span_lint(cx, CAST_PRECISION_LOSS, expr.span,
                                                  &format!("converting from {} to {}, which causes a loss of precision",
                                                           i, f));
                                    },
                                    _ => ()
                                }
                            }
                            (&ty::TypeVariants::TyUint(u), &ty::TypeVariants::TyFloat(f)) => {
                                match (u, f) {
                                    (ast::UintTy::TyU32, ast::FloatTy::TyF32) |
                                    (ast::UintTy::TyU64, ast::FloatTy::TyF32) |
                                    (ast::UintTy::TyU64, ast::FloatTy::TyF64) => {
                                        span_lint(cx, CAST_PRECISION_LOSS, expr.span,
                                                  &format!("converting from {} to {}, which causes a loss of precision",
                                                           u, f));
                                    },
                                    _ => ()
                                }
                            },
                            _ => ()
                        }
                    },
                    (false, true) => {
                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                  &format!("the contents of a {} may overflow a {}", cast_from, cast_to));
                        if !cx.tcx.expr_ty(expr).is_signed() {
                            span_lint(cx, CAST_SIGN_LOSS, expr.span,
                                      &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to));
                        }
                    },
                    (true, true) => {
                        match (&cast_from.sty, &cast_to.sty) {
                            (&ty::TypeVariants::TyInt(i1), &ty::TypeVariants::TyInt(i2)) => {
                                match (i1, i2) {
                                    (ast::IntTy::TyI64, ast::IntTy::TyI32) |
                                    (ast::IntTy::TyI64, ast::IntTy::TyI16) |
                                    (ast::IntTy::TyI64, ast::IntTy::TyI8)  |
                                    (ast::IntTy::TyI32, ast::IntTy::TyI16) |
                                    (ast::IntTy::TyI32, ast::IntTy::TyI8)  |
                                    (ast::IntTy::TyI16, ast::IntTy::TyI8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", i1, i2)),
                                    _ => ()
                                }
                            },
                            (&ty::TypeVariants::TyInt(i), &ty::TypeVariants::TyUint(u)) => {
                                span_lint(cx, CAST_SIGN_LOSS, expr.span,
                                          &format!("casting from {} to {} loses the sign of the value", i, u));
                                match (i, u) {
                                    (ast::IntTy::TyI64, ast::UintTy::TyU32) |
                                    (ast::IntTy::TyI64, ast::UintTy::TyU16) |
                                    (ast::IntTy::TyI64, ast::UintTy::TyU8)  |
                                    (ast::IntTy::TyI32, ast::UintTy::TyU16) |
                                    (ast::IntTy::TyI32, ast::UintTy::TyU8)  |
                                    (ast::IntTy::TyI16, ast::UintTy::TyU8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", i, u)),
                                    _ => ()
                                }
                            },
                            (&ty::TypeVariants::TyUint(u), &ty::TypeVariants::TyInt(i)) => {
                                match (u, i) {
                                    (ast::UintTy::TyU64, ast::IntTy::TyI32) |
                                    (ast::UintTy::TyU64, ast::IntTy::TyI64) |
                                    (ast::UintTy::TyU64, ast::IntTy::TyI16) |
                                    (ast::UintTy::TyU64, ast::IntTy::TyI8)  |
                                    (ast::UintTy::TyU32, ast::IntTy::TyI32) |
                                    (ast::UintTy::TyU32, ast::IntTy::TyI16) |
                                    (ast::UintTy::TyU32, ast::IntTy::TyI8)  |
                                    (ast::UintTy::TyU16, ast::IntTy::TyI16) |
                                    (ast::UintTy::TyU16, ast::IntTy::TyI8)  |
                                    (ast::UintTy::TyU8, ast::IntTy::TyI8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", u, i)),
                                    _ => ()
                                }
                            },
                            (&ty::TypeVariants::TyUint(u1), &ty::TypeVariants::TyUint(u2)) => {
                                match (u1, u2) {
                                    (ast::UintTy::TyU64, ast::UintTy::TyU32) |
                                    (ast::UintTy::TyU64, ast::UintTy::TyU16) |
                                    (ast::UintTy::TyU64, ast::UintTy::TyU8)  |
                                    (ast::UintTy::TyU32, ast::UintTy::TyU16) |
                                    (ast::UintTy::TyU32, ast::UintTy::TyU8)  |
                                    (ast::UintTy::TyU16, ast::UintTy::TyU8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", u1, u2)),
                                    _ => ()
                                }
                            },
                            _ => ()
                        }
                    }
                    (false, false) => {
                        if let (&ty::TypeVariants::TyFloat(ast::FloatTy::TyF64),
                                &ty::TypeVariants::TyFloat(ast::FloatTy::TyF32)) = (&cast_from.sty, &cast_to.sty) {
                            span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, "the contents of a f64 may overflow a f32");
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>Also test that the CastExpr's right arm is numeric.<commit_after>use rustc::lint::*;
use syntax::ast;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::ptr::P;
use rustc::middle::ty;
use syntax::codemap::ExpnInfo;

use utils::{in_macro, snippet, span_lint, span_help_and_lint, in_external_macro};

/// Handles all the linting of funky types
#[allow(missing_copy_implementations)]
pub struct TypePass;

declare_lint!(pub BOX_VEC, Warn,
              "usage of `Box<Vec<T>>`, vector elements are already on the heap");
declare_lint!(pub LINKEDLIST, Warn,
              "usage of LinkedList, usually a vector is faster, or a more specialized data \
               structure like a RingBuf");

/// Matches a type with a provided string, and returns its type parameters if successful
pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
    match ty.node {
        TyPath(_, Path {segments: ref seg, ..}) => {
            // So ast::Path isn't the full path, just the tokens that were provided.
            // I could muck around with the maps and find the full path
            // however the more efficient way is to simply reverse the iterators and zip them
            // which will compare them in reverse until one of them runs out of segments
            if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.name == b) {
                match seg[..].last() {
                    Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => {
                        Some(&a.types[..])
                    }
                    _ => None
                }
            } else {
                None
            }
        },
        _ => None
    }
}

#[allow(unused_imports)]
impl LintPass for TypePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(BOX_VEC, LINKEDLIST)
    }

    fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) {
        {
            // In case stuff gets moved around
            use std::boxed::Box;
            use std::vec::Vec;
        }
        match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first())
          .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"]))
          .map(|_| {
            span_help_and_lint(cx, BOX_VEC, ty.span,
                              "you seem to be trying to use `Box<Vec<T>>`. Did you mean to use `Vec<T>`?",
                              "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation");
          });
        {
            // In case stuff gets moved around
            use collections::linked_list::LinkedList as DL1;
            use std::collections::linked_list::LinkedList as DL2;
        }
        let dlists = [vec!["std","collections","linked_list","LinkedList"],
                      vec!["collections","linked_list","LinkedList"]];
        for path in &dlists {
            if match_ty_unwrap(ty, &path[..]).is_some() {
                span_help_and_lint(cx, LINKEDLIST, ty.span,
                                   "I see you're using a LinkedList! Perhaps you meant some other data structure?",
                                   "a RingBuf might work");
                return;
            }
        }
    }
}

#[allow(missing_copy_implementations)]
pub struct LetPass;

declare_lint!(pub LET_UNIT_VALUE, Warn,
              "creating a let binding to a value of unit type, which usually can't be used afterwards");

fn check_let_unit(cx: &Context, decl: &Decl, info: Option<&ExpnInfo>) {
    if in_macro(cx, info) { return; }
    if let DeclLocal(ref local) = decl.node {
        let bindtype = &cx.tcx.pat_ty(&*local.pat).sty;
        if *bindtype == ty::TyTuple(vec![]) {
            span_lint(cx, LET_UNIT_VALUE, decl.span, &format!(
                "this let-binding has unit value. Consider omitting `let {} =`",
                snippet(cx, local.pat.span, "..")));
        }
    }
}

impl LintPass for LetPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(LET_UNIT_VALUE)
    }

    fn check_decl(&mut self, cx: &Context, decl: &Decl) {
        cx.sess().codemap().with_expn_info(
            decl.span.expn_id,
            |info| check_let_unit(cx, decl, info));
    }
}

declare_lint!(pub UNIT_CMP, Warn,
              "comparing unit values (which is always `true` or `false`, respectively)");

#[allow(missing_copy_implementations)]
pub struct UnitCmp;

impl LintPass for UnitCmp {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNIT_CMP)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprBinary(ref cmp, ref left, _) = expr.node {
            let op = cmp.node;
            let sty = &cx.tcx.expr_ty(left).sty;
            if *sty == ty::TyTuple(vec![]) && is_comparison_binop(op) {
                let result = match op {
                    BiEq | BiLe | BiGe => "true",
                    _ => "false"
                };
                span_lint(cx, UNIT_CMP, expr.span, &format!(
                    "{}-comparison of unit values detected. This will always be {}",
                    binop_to_string(op), result));
            }
        }
    }
}

pub struct CastPass;

declare_lint!(pub CAST_PRECISION_LOSS, Allow,
              "casts that cause loss of precision, e.g `x as f32` where `x: u64`");
declare_lint!(pub CAST_SIGN_LOSS, Allow,
              "casts from signed types to unsigned types, e.g `x as u32` where `x: i32`");
declare_lint!(pub CAST_POSSIBLE_OVERFLOW, Allow,
              "casts that may cause overflow, e.g `x as u8` where `x: u32`, or `x as i32` where `x: f32`");

impl LintPass for CastPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(CAST_PRECISION_LOSS,
                    CAST_SIGN_LOSS,
                    CAST_POSSIBLE_OVERFLOW)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let ExprCast(ref ex, _) = expr.node {
            let (cast_from, cast_to) = (cx.tcx.expr_ty(&*ex), cx.tcx.expr_ty(expr));
            if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx, expr.span) {
                match (cast_from.is_integral(), cast_to.is_integral()) {
                    (true, false)  => {
                        match (&cast_from.sty, &cast_to.sty) {
                            (&ty::TypeVariants::TyInt(i), &ty::TypeVariants::TyFloat(f)) => {
                                match (i, f) {
                                    (ast::IntTy::TyI32, ast::FloatTy::TyF32) |
                                    (ast::IntTy::TyI64, ast::FloatTy::TyF32) |
                                    (ast::IntTy::TyI64, ast::FloatTy::TyF64) => {
                                        span_lint(cx, CAST_PRECISION_LOSS, expr.span,
                                                  &format!("converting from {} to {}, which causes a loss of precision",
                                                           i, f));
                                    },
                                    _ => ()
                                }
                            }
                            (&ty::TypeVariants::TyUint(u), &ty::TypeVariants::TyFloat(f)) => {
                                match (u, f) {
                                    (ast::UintTy::TyU32, ast::FloatTy::TyF32) |
                                    (ast::UintTy::TyU64, ast::FloatTy::TyF32) |
                                    (ast::UintTy::TyU64, ast::FloatTy::TyF64) => {
                                        span_lint(cx, CAST_PRECISION_LOSS, expr.span,
                                                  &format!("converting from {} to {}, which causes a loss of precision",
                                                           u, f));
                                    },
                                    _ => ()
                                }
                            },
                            _ => ()
                        }
                    },
                    (false, true) => {
                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                  &format!("the contents of a {} may overflow a {}", cast_from, cast_to));
                        if !cx.tcx.expr_ty(expr).is_signed() {
                            span_lint(cx, CAST_SIGN_LOSS, expr.span,
                                      &format!("casting from {} to {} loses the sign of the value", cast_from, cast_to));
                        }
                    },
                    (true, true) => {
                        match (&cast_from.sty, &cast_to.sty) {
                            (&ty::TypeVariants::TyInt(i1), &ty::TypeVariants::TyInt(i2)) => {
                                match (i1, i2) {
                                    (ast::IntTy::TyI64, ast::IntTy::TyI32) |
                                    (ast::IntTy::TyI64, ast::IntTy::TyI16) |
                                    (ast::IntTy::TyI64, ast::IntTy::TyI8)  |
                                    (ast::IntTy::TyI32, ast::IntTy::TyI16) |
                                    (ast::IntTy::TyI32, ast::IntTy::TyI8)  |
                                    (ast::IntTy::TyI16, ast::IntTy::TyI8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", i1, i2)),
                                    _ => ()
                                }
                            },
                            (&ty::TypeVariants::TyInt(i), &ty::TypeVariants::TyUint(u)) => {
                                span_lint(cx, CAST_SIGN_LOSS, expr.span,
                                          &format!("casting from {} to {} loses the sign of the value", i, u));
                                match (i, u) {
                                    (ast::IntTy::TyI64, ast::UintTy::TyU32) |
                                    (ast::IntTy::TyI64, ast::UintTy::TyU16) |
                                    (ast::IntTy::TyI64, ast::UintTy::TyU8)  |
                                    (ast::IntTy::TyI32, ast::UintTy::TyU16) |
                                    (ast::IntTy::TyI32, ast::UintTy::TyU8)  |
                                    (ast::IntTy::TyI16, ast::UintTy::TyU8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", i, u)),
                                    _ => ()
                                }
                            },
                            (&ty::TypeVariants::TyUint(u), &ty::TypeVariants::TyInt(i)) => {
                                match (u, i) {
                                    (ast::UintTy::TyU64, ast::IntTy::TyI32) |
                                    (ast::UintTy::TyU64, ast::IntTy::TyI64) |
                                    (ast::UintTy::TyU64, ast::IntTy::TyI16) |
                                    (ast::UintTy::TyU64, ast::IntTy::TyI8)  |
                                    (ast::UintTy::TyU32, ast::IntTy::TyI32) |
                                    (ast::UintTy::TyU32, ast::IntTy::TyI16) |
                                    (ast::UintTy::TyU32, ast::IntTy::TyI8)  |
                                    (ast::UintTy::TyU16, ast::IntTy::TyI16) |
                                    (ast::UintTy::TyU16, ast::IntTy::TyI8)  |
                                    (ast::UintTy::TyU8, ast::IntTy::TyI8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", u, i)),
                                    _ => ()
                                }
                            },
                            (&ty::TypeVariants::TyUint(u1), &ty::TypeVariants::TyUint(u2)) => {
                                match (u1, u2) {
                                    (ast::UintTy::TyU64, ast::UintTy::TyU32) |
                                    (ast::UintTy::TyU64, ast::UintTy::TyU16) |
                                    (ast::UintTy::TyU64, ast::UintTy::TyU8)  |
                                    (ast::UintTy::TyU32, ast::UintTy::TyU16) |
                                    (ast::UintTy::TyU32, ast::UintTy::TyU8)  |
                                    (ast::UintTy::TyU16, ast::UintTy::TyU8) =>
                                        span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span,
                                                  &format!("the contents of a {} may overflow a {}", u1, u2)),
                                    _ => ()
                                }
                            },
                            _ => ()
                        }
                    }
                    (false, false) => {
                        if let (&ty::TypeVariants::TyFloat(ast::FloatTy::TyF64),
                                &ty::TypeVariants::TyFloat(ast::FloatTy::TyF32)) = (&cast_from.sty, &cast_to.sty) {
                            span_lint(cx, CAST_POSSIBLE_OVERFLOW, expr.span, "the contents of a f64 may overflow a f32");
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Custom input types
//!

use traits::{AsBytes, AtEof, Compare, CompareResult, ExtendInto, FindSubstring,
  FindToken, InputIter, InputLength, InputTake, Offset, ParseTo, Slice};

use std::str::{self, CharIndices, Chars, FromStr};
use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
use std::iter::{Enumerate, Map};
use std::slice::Iter;

/// Holds a complete String, for which the `at_eof` method always returns true
///
/// This means that this input type will completely avoid nom's streaming features
/// and `Incomplete` results.
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub struct CompleteStr<'a>(pub &'a str);

impl<'a> AtEof for CompleteStr<'a> {
  fn at_eof(&self) -> bool {
    true
  }
}

impl<'a> Slice<Range<usize>> for CompleteStr<'a> {
  fn slice(&self, range: Range<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeTo<usize>> for CompleteStr<'a> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFrom<usize>> for CompleteStr<'a> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFull> for CompleteStr<'a> {
  fn slice(&self, range: RangeFull) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> InputIter for CompleteStr<'a> {
  type Item = char;
  type RawItem = char;
  type Iter = CharIndices<'a>;
  type IterElem = Chars<'a>;

  fn iter_indices(&self) -> Self::Iter {
    self.0.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.0.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.0.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.0.slice_index(count)
  }
}

impl<'a> InputTake for CompleteStr<'a> {
  fn take(&self, count: usize) -> Self {
    CompleteStr(self.0.take(count))
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.0.take_split(count);
    (CompleteStr(left), CompleteStr(right))
  }
}

impl<'a> InputLength for CompleteStr<'a> {
  fn input_len(&self) -> usize {
    self.0.input_len()
  }
}

impl<'a, 'b> Compare<&'b str> for CompleteStr<'a> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> FindSubstring<&'b str> for CompleteStr<'a> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a> FindToken<char> for CompleteStr<'a> {
  fn find_token(&self, token: char) -> bool {
    self.0.find_token(token)
  }
}

impl<'a> FindToken<u8> for CompleteStr<'a> {
  fn find_token(&self, token: u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, 'b> FindToken<&'a u8> for CompleteStr<'b> {
  fn find_token(&self, token: &u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, R: FromStr> ParseTo<R> for CompleteStr<'a> {
  fn parse_to(&self) -> Option<R> {
    self.0.parse().ok()
  }
}

impl<'a> Offset for CompleteStr<'a> {
  fn offset(&self, second: &CompleteStr<'a>) -> usize {
    self.0.offset(second.0)
  }
}

impl<'a> AsBytes for CompleteStr<'a> {
  fn as_bytes(&self) -> &[u8] {
    AsBytes::as_bytes(self.0)
  }
}

#[cfg(feature = "std")]
impl<'a> ExtendInto for CompleteStr<'a> {
  type Item = char;
  type Extender = String;

  #[inline]
  fn new_builder(&self) -> String {
    String::new()
  }
  #[inline]
  fn extend_into(&self, acc: &mut String) {
    acc.extend(self.0.chars());
  }
}

/// Holds a complete String, for which the `at_eof` method always returns true
///
/// This means that this input type will completely avoid nom's streaming features
/// and `Incomplete` results.
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub struct CompleteByteSlice<'a>(pub &'a [u8]);

impl<'a> AtEof for CompleteByteSlice<'a> {
  fn at_eof(&self) -> bool {
    true
  }
}

impl<'a> Slice<Range<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: Range<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeTo<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFrom<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFull> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeFull) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> InputIter for CompleteByteSlice<'a> {
  type Item = u8;
  type RawItem = u8;
  type Iter = Enumerate<Self::IterElem>;
  type IterElem = Map<Iter<'a, Self::Item>, fn(&u8) -> u8>; //Iter<'a, Self::RawItem>;

  fn iter_indices(&self) -> Self::Iter {
    self.0.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.0.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.0.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.0.slice_index(count)
  }
}

impl<'a> InputTake for CompleteByteSlice<'a> {
  fn take(&self, count: usize) -> Self {
    CompleteByteSlice(self.0.take(count))
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.0.take_split(count);
    (CompleteByteSlice(left), CompleteByteSlice(right))
  }
}

impl<'a> InputLength for CompleteByteSlice<'a> {
  fn input_len(&self) -> usize {
    self.0.input_len()
  }
}

impl<'a, 'b> Compare<&'b [u8]> for CompleteByteSlice<'a> {
  fn compare(&self, t: &'b [u8]) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b [u8]) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> Compare<&'b str> for CompleteByteSlice<'a> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> FindSubstring<&'b [u8]> for CompleteByteSlice<'a> {
  fn find_substring(&self, substr: &'b [u8]) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a, 'b> FindSubstring<&'b str> for CompleteByteSlice<'a> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a> FindToken<char> for CompleteByteSlice<'a> {
  fn find_token(&self, token: char) -> bool {
    self.0.find_token(token)
  }
}

impl<'a> FindToken<u8> for CompleteByteSlice<'a> {
  fn find_token(&self, token: u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, 'b> FindToken<&'a u8> for CompleteByteSlice<'b> {
  fn find_token(&self, token: &u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, R: FromStr> ParseTo<R> for CompleteByteSlice<'a> {
  fn parse_to(&self) -> Option<R> {
    self.0.parse_to()
  }
}

impl<'a> Offset for CompleteByteSlice<'a> {
  fn offset(&self, second: &CompleteByteSlice<'a>) -> usize {
    self.0.offset(second.0)
  }
}

impl<'a> AsBytes for CompleteByteSlice<'a> {
  fn as_bytes(&self) -> &[u8] {
    self.0.as_bytes()
  }
}

#[cfg(feature = "std")]
impl<'a> super::util::HexDisplay for CompleteByteSlice<'a> {
  fn to_hex(&self, chunk_size: usize) -> String {
    self.0.to_hex(chunk_size)
  }

  fn to_hex_from(&self, chunk_size: usize, from: usize) -> String {
    self.0.to_hex_from(chunk_size, from)
  }
}

#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub struct Input<T> {
  pub inner: T,
  pub at_eof: bool,
}

impl<T> AtEof for Input<T> {
  fn at_eof(&self) -> bool {
    self.at_eof
  }
}

impl<T: Slice<Range<usize>>> Slice<Range<usize>> for Input<T> {
  fn slice(&self, range: Range<usize>) -> Self {
    Input {
      inner: self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: Slice<RangeTo<usize>>> Slice<RangeTo<usize>> for Input<T> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    Input {
      inner: self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: Slice<RangeFrom<usize>>> Slice<RangeFrom<usize>> for Input<T> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    Input {
      inner: self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: Slice<RangeFull>> Slice<RangeFull> for Input<T> {
  fn slice(&self, range: RangeFull) -> Self {
    Input {
      inner: self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: InputIter> InputIter for Input<T> {
  type Item = <T as InputIter>::Item;
  type RawItem = <T as InputIter>::RawItem;
  type Iter = <T as InputIter>::Iter;
  type IterElem = <T as InputIter>::IterElem;

  fn iter_indices(&self) -> Self::Iter {
    self.inner.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.inner.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.inner.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.inner.slice_index(count)
  }
}

impl<T: InputTake> InputTake for Input<T> {
  fn take(&self, count: usize) -> Self {
    Input {
      inner: self.inner.take(count),
      at_eof: self.at_eof,
    }
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.inner.take_split(count);
    (
      Input {
        inner: left,
        at_eof: self.at_eof,
      },
      Input {
        inner: right,
        at_eof: self.at_eof,
      },
    )
  }
}

impl<T: InputLength> InputLength for Input<T> {
  fn input_len(&self) -> usize {
    self.inner.input_len()
  }
}

impl<'b, T: Compare<&'b str>> Compare<&'b str> for Input<T> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.inner.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.inner.compare_no_case(t)
  }
}

impl<'b, T: FindSubstring<&'b str>> FindSubstring<&'b str> for Input<T> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.inner.find_substring(substr)
  }
}

impl<T: FindToken<char>> FindToken<char> for Input<T> {
  fn find_token(&self, token: char) -> bool {
    self.inner.find_token(token)
  }
}

impl<T: FindToken<u8>> FindToken<u8> for Input<T> {
  fn find_token(&self, token: u8) -> bool {
    self.inner.find_token(token)
  }
}

impl<'a, T: FindToken<&'a u8>> FindToken<&'a u8> for Input<T> {
  fn find_token(&self, token: &'a u8) -> bool {
    self.inner.find_token(token)
  }
}

impl<'a, R: FromStr, T: ParseTo<R>> ParseTo<R> for Input<T> {
  fn parse_to(&self) -> Option<R> {
    self.inner.parse_to()
  }
}

impl<T: Offset> Offset for Input<T> {
  fn offset(&self, second: &Input<T>) -> usize {
    self.inner.offset(&second.inner)
  }
}

impl<T: AsBytes> AsBytes for Input<T> {
  fn as_bytes(&self) -> &[u8] {
    AsBytes::as_bytes(&self.inner)
  }
}
<commit_msg>missing derives<commit_after>//! Custom input types
//!

use traits::{AsBytes, AtEof, Compare, CompareResult, ExtendInto, FindSubstring,
  FindToken, InputIter, InputLength, InputTake, Offset, ParseTo, Slice};

use std::str::{self, CharIndices, Chars, FromStr};
use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
use std::iter::{Enumerate, Map};
use std::slice::Iter;

/// Holds a complete String, for which the `at_eof` method always returns true
///
/// This means that this input type will completely avoid nom's streaming features
/// and `Incomplete` results.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct CompleteStr<'a>(pub &'a str);

impl<'a> AtEof for CompleteStr<'a> {
  fn at_eof(&self) -> bool {
    true
  }
}

impl<'a> Slice<Range<usize>> for CompleteStr<'a> {
  fn slice(&self, range: Range<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeTo<usize>> for CompleteStr<'a> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFrom<usize>> for CompleteStr<'a> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFull> for CompleteStr<'a> {
  fn slice(&self, range: RangeFull) -> Self {
    CompleteStr(self.0.slice(range))
  }
}

impl<'a> InputIter for CompleteStr<'a> {
  type Item = char;
  type RawItem = char;
  type Iter = CharIndices<'a>;
  type IterElem = Chars<'a>;

  fn iter_indices(&self) -> Self::Iter {
    self.0.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.0.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.0.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.0.slice_index(count)
  }
}

impl<'a> InputTake for CompleteStr<'a> {
  fn take(&self, count: usize) -> Self {
    CompleteStr(self.0.take(count))
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.0.take_split(count);
    (CompleteStr(left), CompleteStr(right))
  }
}

impl<'a> InputLength for CompleteStr<'a> {
  fn input_len(&self) -> usize {
    self.0.input_len()
  }
}

impl<'a, 'b> Compare<&'b str> for CompleteStr<'a> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> FindSubstring<&'b str> for CompleteStr<'a> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a> FindToken<char> for CompleteStr<'a> {
  fn find_token(&self, token: char) -> bool {
    self.0.find_token(token)
  }
}

impl<'a> FindToken<u8> for CompleteStr<'a> {
  fn find_token(&self, token: u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, 'b> FindToken<&'a u8> for CompleteStr<'b> {
  fn find_token(&self, token: &u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, R: FromStr> ParseTo<R> for CompleteStr<'a> {
  fn parse_to(&self) -> Option<R> {
    self.0.parse().ok()
  }
}

impl<'a> Offset for CompleteStr<'a> {
  fn offset(&self, second: &CompleteStr<'a>) -> usize {
    self.0.offset(second.0)
  }
}

impl<'a> AsBytes for CompleteStr<'a> {
  fn as_bytes(&self) -> &[u8] {
    AsBytes::as_bytes(self.0)
  }
}

#[cfg(feature = "std")]
impl<'a> ExtendInto for CompleteStr<'a> {
  type Item = char;
  type Extender = String;

  #[inline]
  fn new_builder(&self) -> String {
    String::new()
  }
  #[inline]
  fn extend_into(&self, acc: &mut String) {
    acc.extend(self.0.chars());
  }
}

/// Holds a complete String, for which the `at_eof` method always returns true
///
/// This means that this input type will completely avoid nom's streaming features
/// and `Incomplete` results.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct CompleteByteSlice<'a>(pub &'a [u8]);

impl<'a> AtEof for CompleteByteSlice<'a> {
  fn at_eof(&self) -> bool {
    true
  }
}

impl<'a> Slice<Range<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: Range<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeTo<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFrom<usize>> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> Slice<RangeFull> for CompleteByteSlice<'a> {
  fn slice(&self, range: RangeFull) -> Self {
    CompleteByteSlice(self.0.slice(range))
  }
}

impl<'a> InputIter for CompleteByteSlice<'a> {
  type Item = u8;
  type RawItem = u8;
  type Iter = Enumerate<Self::IterElem>;
  type IterElem = Map<Iter<'a, Self::Item>, fn(&u8) -> u8>; //Iter<'a, Self::RawItem>;

  fn iter_indices(&self) -> Self::Iter {
    self.0.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.0.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.0.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.0.slice_index(count)
  }
}

impl<'a> InputTake for CompleteByteSlice<'a> {
  fn take(&self, count: usize) -> Self {
    CompleteByteSlice(self.0.take(count))
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.0.take_split(count);
    (CompleteByteSlice(left), CompleteByteSlice(right))
  }
}

impl<'a> InputLength for CompleteByteSlice<'a> {
  fn input_len(&self) -> usize {
    self.0.input_len()
  }
}

impl<'a, 'b> Compare<&'b [u8]> for CompleteByteSlice<'a> {
  fn compare(&self, t: &'b [u8]) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b [u8]) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> Compare<&'b str> for CompleteByteSlice<'a> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.0.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.0.compare_no_case(t)
  }
}

impl<'a, 'b> FindSubstring<&'b [u8]> for CompleteByteSlice<'a> {
  fn find_substring(&self, substr: &'b [u8]) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a, 'b> FindSubstring<&'b str> for CompleteByteSlice<'a> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.0.find_substring(substr)
  }
}

impl<'a> FindToken<char> for CompleteByteSlice<'a> {
  fn find_token(&self, token: char) -> bool {
    self.0.find_token(token)
  }
}

impl<'a> FindToken<u8> for CompleteByteSlice<'a> {
  fn find_token(&self, token: u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, 'b> FindToken<&'a u8> for CompleteByteSlice<'b> {
  fn find_token(&self, token: &u8) -> bool {
    self.0.find_token(token)
  }
}

impl<'a, R: FromStr> ParseTo<R> for CompleteByteSlice<'a> {
  fn parse_to(&self) -> Option<R> {
    self.0.parse_to()
  }
}

impl<'a> Offset for CompleteByteSlice<'a> {
  fn offset(&self, second: &CompleteByteSlice<'a>) -> usize {
    self.0.offset(second.0)
  }
}

impl<'a> AsBytes for CompleteByteSlice<'a> {
  fn as_bytes(&self) -> &[u8] {
    self.0.as_bytes()
  }
}

#[cfg(feature = "std")]
impl<'a> super::util::HexDisplay for CompleteByteSlice<'a> {
  fn to_hex(&self, chunk_size: usize) -> String {
    self.0.to_hex(chunk_size)
  }

  fn to_hex_from(&self, chunk_size: usize, from: usize) -> String {
    self.0.to_hex_from(chunk_size, from)
  }
}

#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub struct Input<T> {
  pub inner: T,
  pub at_eof: bool,
}

impl<T> AtEof for Input<T> {
  fn at_eof(&self) -> bool {
    self.at_eof
  }
}

impl<T: Slice<Range<usize>>> Slice<Range<usize>> for Input<T> {
  fn slice(&self, range: Range<usize>) -> Self {
    Input {
      inner: self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: Slice<RangeTo<usize>>> Slice<RangeTo<usize>> for Input<T> {
  fn slice(&self, range: RangeTo<usize>) -> Self {
    Input {
      inner: self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: Slice<RangeFrom<usize>>> Slice<RangeFrom<usize>> for Input<T> {
  fn slice(&self, range: RangeFrom<usize>) -> Self {
    Input {
      inner: self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: Slice<RangeFull>> Slice<RangeFull> for Input<T> {
  fn slice(&self, range: RangeFull) -> Self {
    Input {
      inner: self.inner.slice(range),
      at_eof: self.at_eof,
    }
  }
}

impl<T: InputIter> InputIter for Input<T> {
  type Item = <T as InputIter>::Item;
  type RawItem = <T as InputIter>::RawItem;
  type Iter = <T as InputIter>::Iter;
  type IterElem = <T as InputIter>::IterElem;

  fn iter_indices(&self) -> Self::Iter {
    self.inner.iter_indices()
  }
  fn iter_elements(&self) -> Self::IterElem {
    self.inner.iter_elements()
  }
  fn position<P>(&self, predicate: P) -> Option<usize>
  where
    P: Fn(Self::RawItem) -> bool,
  {
    self.inner.position(predicate)
  }
  fn slice_index(&self, count: usize) -> Option<usize> {
    self.inner.slice_index(count)
  }
}

impl<T: InputTake> InputTake for Input<T> {
  fn take(&self, count: usize) -> Self {
    Input {
      inner: self.inner.take(count),
      at_eof: self.at_eof,
    }
  }

  fn take_split(&self, count: usize) -> (Self, Self) {
    let (left, right) = self.inner.take_split(count);
    (
      Input {
        inner: left,
        at_eof: self.at_eof,
      },
      Input {
        inner: right,
        at_eof: self.at_eof,
      },
    )
  }
}

impl<T: InputLength> InputLength for Input<T> {
  fn input_len(&self) -> usize {
    self.inner.input_len()
  }
}

impl<'b, T: Compare<&'b str>> Compare<&'b str> for Input<T> {
  fn compare(&self, t: &'b str) -> CompareResult {
    self.inner.compare(t)
  }
  fn compare_no_case(&self, t: &'b str) -> CompareResult {
    self.inner.compare_no_case(t)
  }
}

impl<'b, T: FindSubstring<&'b str>> FindSubstring<&'b str> for Input<T> {
  fn find_substring(&self, substr: &'b str) -> Option<usize> {
    self.inner.find_substring(substr)
  }
}

impl<T: FindToken<char>> FindToken<char> for Input<T> {
  fn find_token(&self, token: char) -> bool {
    self.inner.find_token(token)
  }
}

impl<T: FindToken<u8>> FindToken<u8> for Input<T> {
  fn find_token(&self, token: u8) -> bool {
    self.inner.find_token(token)
  }
}

impl<'a, T: FindToken<&'a u8>> FindToken<&'a u8> for Input<T> {
  fn find_token(&self, token: &'a u8) -> bool {
    self.inner.find_token(token)
  }
}

impl<'a, R: FromStr, T: ParseTo<R>> ParseTo<R> for Input<T> {
  fn parse_to(&self) -> Option<R> {
    self.inner.parse_to()
  }
}

impl<T: Offset> Offset for Input<T> {
  fn offset(&self, second: &Input<T>) -> usize {
    self.inner.offset(&second.inner)
  }
}

impl<T: AsBytes> AsBytes for Input<T> {
  fn as_bytes(&self) -> &[u8] {
    AsBytes::as_bytes(&self.inner)
  }
}
<|endoftext|>


<commit_before>use id::get_id;
use std::collections::HashMap;
use std::ops::Deref;

pub type Id = usize;

#[derive(Debug)]
pub enum PlayZoneKind {
	Battlefield,
	Hand(Id)
}

#[derive(Debug)]
pub enum EntityKind {
	Card,
}

#[derive(Debug)]
pub struct EntityDescriptor {
	pub name: String,
	pub id: Id,
}

#[derive(Debug)]
pub struct EntityDescriptorSet {
	pub map: HashMap<Id, EntityDescriptor>,
}

impl EntityDescriptorSet {
	pub fn new() -> EntityDescriptorSet {
		EntityDescriptorSet {
			map: HashMap::new(),
		}
	}

	pub fn add(&mut self, descriptor: EntityDescriptor) {
		self.map.insert(descriptor.id, descriptor);
	}
}

impl Deref for EntityDescriptorSet {
	type Target = HashMap<Id, EntityDescriptor>;

	fn deref(&self) -> &HashMap<Id, EntityDescriptor> {
		&self.map
	}
}

#[derive(Debug)]
pub struct Entity {
	pub kind: EntityKind,
	pub descriptorId: Id,
}

#[derive(Debug)]
pub struct PlayZone {
	pub kind: PlayZoneKind,
	pub id: Id,
	pub entities: Vec<Entity>,
}

impl PlayZone {
	pub fn new(id: Id, kind: PlayZoneKind) -> PlayZone {
		PlayZone {
			id,
			kind,
			entities: Vec::new(),
		}
	}
}

#[derive(Debug)]
pub struct ManaPool {
	// November 4, 2019 B&R announcement:
	// Standard:
	//  * Island is banned.
	//  * Mountain is banned.
	//  * Swamp is banned.
	//  * Plains is banned.
	pub green: usize,
}

impl ManaPool {
	pub fn new() -> ManaPool {
		ManaPool {
			green: 0,
		}
	}
}

#[derive(Debug)]
pub struct Player {
	pub id: Id,
	pub mana_pool: ManaPool,
}

impl Player {
	pub fn new(id: Id) -> Player {
		Player {
			id,
			mana_pool: ManaPool::new(),
		}
	}
}

#[derive(Debug)]
pub enum PlayStep {
	Untap,
	Main1,
}

#[derive(Debug)]
pub enum PlayAction {
	GainPriority(Id),
	PassPriority(Id),
	StartResolution,
}

impl PlayAction {
	pub fn can_undo(&self) -> bool {
		match *self {
			_ => false,
		}
	}
}

#[derive(Debug)]
pub struct PlayState<'a> {
	pub descriptor_set: &'a EntityDescriptorSet,
	pub zones: HashMap<Id, PlayZone>,
	pub players: HashMap<Id, Player>,
	pub history: Vec<PlayAction>,
}

impl<'a> PlayState<'a> {
	pub fn new(descriptor_set: &EntityDescriptorSet) -> PlayState {
		PlayState {
			descriptor_set,
			zones: HashMap::new(),
			players: HashMap::new(),
			history: Vec::new(),
		}
	}

	pub fn new_default(players: Vec<Player>, descriptor_set: &'a EntityDescriptorSet) -> PlayState<'a> {
		let mut creating = PlayState::new(descriptor_set);

		let battlefield_id = get_id();
		creating.zones.insert(battlefield_id, PlayZone::new(battlefield_id, PlayZoneKind::Battlefield));

		for player in players.into_iter() {
			let hand_id = get_id();
			let hand = PlayZone::new(hand_id, PlayZoneKind::Hand(player.id));
			creating.zones.insert(hand_id, hand);

			creating.players.insert(player.id, player);
		}

		creating
	}

	pub fn undo(&mut self) -> bool {
		match self.history.last() {
			Some(action) => {
				if !action.can_undo() {
					return false;
				}
			},
			None => return false,
		}

		// TODO: actually perform undo

		return true;
	}
}<commit_msg>Update B&R announcement date<commit_after>use id::get_id;
use std::collections::HashMap;
use std::ops::Deref;

pub type Id = usize;

#[derive(Debug)]
pub enum PlayZoneKind {
	Battlefield,
	Hand(Id)
}

#[derive(Debug)]
pub enum EntityKind {
	Card,
}

#[derive(Debug)]
pub struct EntityDescriptor {
	pub name: String,
	pub id: Id,
}

#[derive(Debug)]
pub struct EntityDescriptorSet {
	pub map: HashMap<Id, EntityDescriptor>,
}

impl EntityDescriptorSet {
	pub fn new() -> EntityDescriptorSet {
		EntityDescriptorSet {
			map: HashMap::new(),
		}
	}

	pub fn add(&mut self, descriptor: EntityDescriptor) {
		self.map.insert(descriptor.id, descriptor);
	}
}

impl Deref for EntityDescriptorSet {
	type Target = HashMap<Id, EntityDescriptor>;

	fn deref(&self) -> &HashMap<Id, EntityDescriptor> {
		&self.map
	}
}

#[derive(Debug)]
pub struct Entity {
	pub kind: EntityKind,
	pub descriptorId: Id,
}

#[derive(Debug)]
pub struct PlayZone {
	pub kind: PlayZoneKind,
	pub id: Id,
	pub entities: Vec<Entity>,
}

impl PlayZone {
	pub fn new(id: Id, kind: PlayZoneKind) -> PlayZone {
		PlayZone {
			id,
			kind,
			entities: Vec::new(),
		}
	}
}

#[derive(Debug)]
pub struct ManaPool {
	// October 17, 2017 B&R announcement:
	// Standard:
	//  * Island is banned.
	//  * Mountain is banned.
	//  * Swamp is banned.
	//  * Plains is banned.
	pub green: usize,
}

impl ManaPool {
	pub fn new() -> ManaPool {
		ManaPool {
			green: 0,
		}
	}
}

#[derive(Debug)]
pub struct Player {
	pub id: Id,
	pub mana_pool: ManaPool,
}

impl Player {
	pub fn new(id: Id) -> Player {
		Player {
			id,
			mana_pool: ManaPool::new(),
		}
	}
}

#[derive(Debug)]
pub enum PlayStep {
	Untap,
	Main1,
}

#[derive(Debug)]
pub enum PlayAction {
	GainPriority(Id),
	PassPriority(Id),
	StartResolution,
}

impl PlayAction {
	pub fn can_undo(&self) -> bool {
		match *self {
			_ => false,
		}
	}
}

#[derive(Debug)]
pub struct PlayState<'a> {
	pub descriptor_set: &'a EntityDescriptorSet,
	pub zones: HashMap<Id, PlayZone>,
	pub players: HashMap<Id, Player>,
	pub history: Vec<PlayAction>,
}

impl<'a> PlayState<'a> {
	pub fn new(descriptor_set: &EntityDescriptorSet) -> PlayState {
		PlayState {
			descriptor_set,
			zones: HashMap::new(),
			players: HashMap::new(),
			history: Vec::new(),
		}
	}

	pub fn new_default(players: Vec<Player>, descriptor_set: &'a EntityDescriptorSet) -> PlayState<'a> {
		let mut creating = PlayState::new(descriptor_set);

		let battlefield_id = get_id();
		creating.zones.insert(battlefield_id, PlayZone::new(battlefield_id, PlayZoneKind::Battlefield));

		for player in players.into_iter() {
			let hand_id = get_id();
			let hand = PlayZone::new(hand_id, PlayZoneKind::Hand(player.id));
			creating.zones.insert(hand_id, hand);

			creating.players.insert(player.id, player);
		}

		creating
	}

	pub fn undo(&mut self) -> bool {
		match self.history.last() {
			Some(action) => {
				if !action.can_undo() {
					return false;
				}
			},
			None => return false,
		}

		// TODO: actually perform undo

		return true;
	}
}<|endoftext|>


<commit_before>#![feature(box_syntax,box_patterns)]
#![feature(compile)]
#![feature(scheme)]

/// Scheme compiler integration tests
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd).
/// And from http://webdocs.cs.ualberta.ca/%7Eyou/courses/325/Mynotes/Fun/SECD-slides.html

#[macro_use]
extern crate seax_svm as svm;
extern crate seax_scheme as scheme;

use svm::slist::List::{Cons,Nil};
use svm::cell::Atom::*;
use svm::cell::SVMCell::*;
use svm::Inst::*;

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn compile_list_creation() {
    assert_eq!(
        scheme::compile("(cons 10 (cons 20 nil))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 20 (cons 10 nil)))
/// ```
#[test]
fn  compile_list_car() {
    assert_eq!(
        scheme::compile("(car (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CAR)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 20 (cons 10 nil)))
/// ```
#[test]
fn compile_list_cdr() {
    assert_eq!(
        scheme::compile("(cdr (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
        ))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn compile_simple_add(){
    assert_eq!(
        scheme::compile("(+ 10 10)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn compile_nested_arith() {
     assert_eq!(
        scheme::compile("(- 20 (+ 5 5))"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(ADD),
            InstCell(LDC), AtomCell(SInt(20)),
            InstCell(SUB)
        ))
    );
}

/// Tests for basic branching
///
/// ```lisp
/// (if (= 0 (- 1 1)) #t #f)
/// ```
#[test]
fn compile_basic_branching_1() {
    assert_eq!(
        scheme::compile("(if (= 0 (- 1 1)) #t #f)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
            InstCell(SUB),
            InstCell(LDC), AtomCell(SInt(0)),
            InstCell(EQ),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
                ListCell(box list!(InstCell(NIL), InstCell(JOIN))
            )
        ))
    );
}
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ```
#[test]
fn compile_basic_branching_2() {
    assert_eq!(
        scheme::compile("(+ 10 (if (nil? nil) 10 20))"),
        Ok(list!(
            InstCell(NIL), InstCell(NULL),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(10)), InstCell(JOIN))),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(20)), InstCell(JOIN))),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Lambda
///
/// ```lisp
/// (lambda (x y) (+ x y))
/// ```
///
/// (LDF (LD (1.2) LD (1.1) + RTN))
#[test]
fn compile_lambda() {
    assert_eq!(
        scheme::compile("(lambda (x y) (+ x y))"),
        Ok(list!(
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(UInt(1)), AtomCell(UInt(2))
                    )),
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(UInt(1)), AtomCell(UInt(1))
                    )),
                InstCell(ADD),
                InstCell(RET)
            ))
        ))
    )
}

/// Lambda application
///
/// ```lisp
/// ((lambda (x y) (+ x y)) 2 3)
/// ```
///
/// (NIL LDC 3 CONS LDC 2 CONS LDF (LD (1.2) LD (1.1) + RTN) AP)
#[test]
fn compile_lambda_ap() {
    assert_eq!(
        scheme::compile("((lambda (x y) (+ x y)) 2 3)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(3)),
            InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(2)),
            InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD), ListCell(box list!(
                    AtomCell(UInt(1)), AtomCell(UInt(2))
                    )),
                InstCell(LD), ListCell(box list!(
                    AtomCell(UInt(1)), AtomCell(UInt(1))
                    )),
                InstCell(ADD),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    )
}

/// Nested lambdas
///
/// ```lisp
/// ((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)
/// ```
///
/// ```seax
/// (NIL LDC 6 CONS LDF
///     (NIL LDC 5 CONS LDC 3 CONS
///         LDF
///             (LD (2.1) LD (1.2) LD (1.1) SUB ADD RTN)
///         AP
///         RTN)
///     AP
/// ```
#[test]
fn compile_nested_lambda() {
    assert_eq!(
        scheme::compile("((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(6)), InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(NIL),
                InstCell(LDC), AtomCell(SInt(5)), InstCell(CONS),
                InstCell(LDC), AtomCell(SInt(3)), InstCell(CONS),
                InstCell(LDF),
                ListCell(box list!(
                    InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(2)),AtomCell(UInt(1))
                        )),
                    InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(2))
                        )),
                    InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(1))
                        )),
                    InstCell(SUB),
                    InstCell(ADD),
                    InstCell(RET)
                )),
                InstCell(AP),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    )
}

/// Test for the compilation of a single simple `let` binding.
///
/// ```lisp
/// (let ([x 5]) x)
/// ```
#[test]
fn compile_single_let() {
    assert_eq!(
        scheme::compile("(let ([x 5]) x)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(5)), InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(1))
                    )),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    );
}

/// Test for the compilation of multiple simple `let` bindings.
///
/// ```lisp
/// (let ([x 1]
///       [y 2]
///       [z 3])
///      (+ x y z))
/// ```
#[test]
fn compile_multiple_let() {
    assert_eq!(
        scheme::compile(
            "(let ([x 1]
                   [y 2]
                   [z 3])
                (+ x y z))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(1)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(2)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(3)), InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(3))
                    )),
                InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(2))
                    )),
                InstCell(ADD),
                InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(1))
                    )),
                InstCell(ADD),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    );
}

/// Test for the compilation of a `let` binding to the result of
/// an expression.
///
/// ```lisp
/// (let ([x (+ 1 1)]) x
/// ```
#[test]
fn compile_expr_let() {
    assert_eq!(
        scheme::compile("(let ([x (+ 1 1)]) x)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(1)),
            InstCell(LDC), AtomCell(SInt(1)),
            InstCell(ADD),
            InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(1))
                    )),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    );
}
<commit_msg>Add a test for compilation of a `let` binding with name shadowing<commit_after>#![feature(box_syntax,box_patterns)]
#![feature(compile)]
#![feature(scheme)]

/// Scheme compiler integration tests
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd).
/// And from http://webdocs.cs.ualberta.ca/%7Eyou/courses/325/Mynotes/Fun/SECD-slides.html

#[macro_use]
extern crate seax_svm as svm;
extern crate seax_scheme as scheme;

use svm::slist::List::{Cons,Nil};
use svm::cell::Atom::*;
use svm::cell::SVMCell::*;
use svm::Inst::*;

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn compile_list_creation() {
    assert_eq!(
        scheme::compile("(cons 10 (cons 20 nil))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 20 (cons 10 nil)))
/// ```
#[test]
fn  compile_list_car() {
    assert_eq!(
        scheme::compile("(car (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CAR)
        ))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 20 (cons 10 nil)))
/// ```
#[test]
fn compile_list_cdr() {
    assert_eq!(
        scheme::compile("(cdr (cons 20 (cons 10 nil)))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
        ))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn compile_simple_add(){
    assert_eq!(
        scheme::compile("(+ 10 10)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn compile_nested_arith() {
     assert_eq!(
        scheme::compile("(- 20 (+ 5 5))"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(ADD),
            InstCell(LDC), AtomCell(SInt(20)),
            InstCell(SUB)
        ))
    );
}

/// Tests for basic branching
///
/// ```lisp
/// (if (= 0 (- 1 1)) #t #f)
/// ```
#[test]
fn compile_basic_branching_1() {
    assert_eq!(
        scheme::compile("(if (= 0 (- 1 1)) #t #f)"),
        Ok(list!(
            InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
            InstCell(SUB),
            InstCell(LDC), AtomCell(SInt(0)),
            InstCell(EQ),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
                ListCell(box list!(InstCell(NIL), InstCell(JOIN))
            )
        ))
    );
}
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ```
#[test]
fn compile_basic_branching_2() {
    assert_eq!(
        scheme::compile("(+ 10 (if (nil? nil) 10 20))"),
        Ok(list!(
            InstCell(NIL), InstCell(NULL),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(10)), InstCell(JOIN))),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(20)), InstCell(JOIN))),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ))
    );
}

/// Lambda
///
/// ```lisp
/// (lambda (x y) (+ x y))
/// ```
///
/// (LDF (LD (1.2) LD (1.1) + RTN))
#[test]
fn compile_lambda() {
    assert_eq!(
        scheme::compile("(lambda (x y) (+ x y))"),
        Ok(list!(
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(UInt(1)), AtomCell(UInt(2))
                    )),
                InstCell(LD),
                ListCell(box list!(
                    AtomCell(UInt(1)), AtomCell(UInt(1))
                    )),
                InstCell(ADD),
                InstCell(RET)
            ))
        ))
    )
}

/// Lambda application
///
/// ```lisp
/// ((lambda (x y) (+ x y)) 2 3)
/// ```
///
/// (NIL LDC 3 CONS LDC 2 CONS LDF (LD (1.2) LD (1.1) + RTN) AP)
#[test]
fn compile_lambda_ap() {
    assert_eq!(
        scheme::compile("((lambda (x y) (+ x y)) 2 3)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(3)),
            InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(2)),
            InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD), ListCell(box list!(
                    AtomCell(UInt(1)), AtomCell(UInt(2))
                    )),
                InstCell(LD), ListCell(box list!(
                    AtomCell(UInt(1)), AtomCell(UInt(1))
                    )),
                InstCell(ADD),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    )
}

/// Nested lambdas
///
/// ```lisp
/// ((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)
/// ```
///
/// ```seax
/// (NIL LDC 6 CONS LDF
///     (NIL LDC 5 CONS LDC 3 CONS
///         LDF
///             (LD (2.1) LD (1.2) LD (1.1) SUB ADD RTN)
///         AP
///         RTN)
///     AP
/// ```
#[test]
fn compile_nested_lambda() {
    assert_eq!(
        scheme::compile("((lambda (z) ((lambda (x y) (+ (- x y) z)) 3 5)) 6)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(6)), InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(NIL),
                InstCell(LDC), AtomCell(SInt(5)), InstCell(CONS),
                InstCell(LDC), AtomCell(SInt(3)), InstCell(CONS),
                InstCell(LDF),
                ListCell(box list!(
                    InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(2)),AtomCell(UInt(1))
                        )),
                    InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(2))
                        )),
                    InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(1))
                        )),
                    InstCell(SUB),
                    InstCell(ADD),
                    InstCell(RET)
                )),
                InstCell(AP),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    )
}

/// Test for the compilation of a single simple `let` binding.
///
/// ```lisp
/// (let ([x 5]) x)
/// ```
#[test]
fn compile_single_let() {
    assert_eq!(
        scheme::compile("(let ([x 5]) x)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(5)), InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(1))
                    )),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    );
}

/// Test for the compilation of multiple simple `let` bindings.
///
/// ```lisp
/// (let ([x 1]
///       [y 2]
///       [z 3])
///      (+ x y z))
/// ```
#[test]
fn compile_multiple_let() {
    assert_eq!(
        scheme::compile(
            "(let ([x 1]
                   [y 2]
                   [z 3])
                (+ x y z))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(1)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(2)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(3)), InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(3))
                    )),
                InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(2))
                    )),
                InstCell(ADD),
                InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(1))
                    )),
                InstCell(ADD),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    );
}

/// Test for the compilation of a `let` binding to the result of
/// an expression.
///
/// ```lisp
/// (let ([x (+ 1 1)]) x
/// ```
#[test]
fn compile_expr_let() {
    assert_eq!(
        scheme::compile("(let ([x (+ 1 1)]) x)"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(1)),
            InstCell(LDC), AtomCell(SInt(1)),
            InstCell(ADD),
            InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(LD), ListCell(box list!(
                        AtomCell(UInt(1)),AtomCell(UInt(1))
                    )),
                InstCell(RET)
            )),
            InstCell(AP)
        ))
    );
}

/// Test for the compilation of a `let` binding with name shadowing
///
/// ```lisp
/// (let ([x 1])
///     (let ([x 2]) x)
///     )
/// ```
#[test]
fn compile_name_shadowing_let() {
    assert_eq!(
        scheme::compile("(let ([x 1])
                            (let ([x 2]) x))"),
        Ok(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(1)),
            InstCell(CONS),
            InstCell(LDF),
            ListCell(box list!(
                InstCell(NIL),
                InstCell(LDC), AtomCell(SInt(2)),
                InstCell(CONS),
                InstCell(LDF),
                ListCell(box list!(
                    InstCell(LD), ListCell(box list!(
                            AtomCell(UInt(1)),AtomCell(UInt(1))
                        )),
                InstCell(RET)
                )),
            InstCell(AP),
            InstCell(RET)
            )),
            InstCell(AP)
        ))
    );
}

<|endoftext|>


<commit_before>#![doc(html_root_url = "https://urschrei.github.io/lonlat_bng/")]
//! This module provides utilities to the conversions module
use conversions::MIN_X_SHIFT;
use conversions::MIN_Y_SHIFT;
use conversions::MIN_Z_SHIFT;

use std;
use std::fmt;
use ostn02_phf::ostn02_lookup;
include!("hexkeys.rs");

// fn helmert(lon_vec: [&f64], lat_vec: [&f64]) -> (Vec<f64>, Vec<f64>) {
//     let t_array = Vec3::new(TX, TY, TZ);
//     let params = Mat3::new(1. + s, RZS, -RYS, -RZS, 1. + s, RXS, RYS, -RXS, 1. + s);
//     // let zeros: Vec<&f64> = vec![&1.; lon_vec.len()];
//     let test = vec![1, 2, 3, 4, 5, 6];
//     // let mut combined: Vec<&f64> = lon_vec.extend(lat_vec.iter()).collect();
//     // combined.extend(zeros.iter().cloned());
//     // let tmat = DMat::from_row_vec(3, zeros.len(), &combined);
//     let tmat = DMat::from_row_vec(3, 2, &test);
//     // build input vector of x, y, and z columns
//     // let inp = DMat::from_row_vec(3, 1, vec![lon_vec, lat_vec, h_vec]);
//     (vec![1.], vec![2.])
// }

/// Bounds checking for input values
pub fn check<T>(to_check: T, bounds: (T, T)) -> Result<T, ()>
    where T: std::cmp::PartialOrd + fmt::Display + Copy
{
    match to_check {
        to_check if bounds.0 <= to_check && to_check <= bounds.1 => Ok(to_check),
        _ => Err(()),
    }
}

pub trait ToMm {
    fn round_to_mm(self) -> f64;
}

impl ToMm for f64 {
    fn round_to_mm(self) -> f64 {
        (self * 1000.).round() as f64 / 1000.
    }
}

/// Round a float to eight decimal places
pub fn round_to_eight(x: f64, y: f64) -> (f64, f64) {
    let new_x = (x * 100000000.).round() as f64 / 100000000.;
    let new_y = (y * 100000000.).round() as f64 / 100000000.;
    (new_x, new_y)
}

/// Try to get OSTN02 shift parameters, and calculate offsets
pub fn get_ostn_ref(x: &i32, y: &i32) -> Result<(f64, f64, f64), ()> {
    // let key = format!("{:03x}{:03x}", y, x);
    // optimisation from https://github.com/hoodie/concatenation_benchmarks-rs
    let mut key = String::with_capacity(32);
    key.push_str(HEXKEYS.get(y).unwrap());
    key.push_str(HEXKEYS.get(x).unwrap());
    // Some or None, so convert to Result, which we can try!
    let result = try!(ostn02_lookup(&*key).ok_or(()));
    Ok((result.0 as f64 / 1000. + MIN_X_SHIFT,
        result.1 as f64 / 1000. + MIN_Y_SHIFT,
        result.2 as f64 / 1000. + MIN_Z_SHIFT))

}

// Input values must be valid ETRS89 grid references
// See p20 of the transformation user guide at
// https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html
/// Calculate OSTN02 shifts for a given coordinate
pub fn ostn02_shifts(x: &f64, y: &f64) -> Result<(f64, f64, f64), ()> {
    let e_index = (*x / 1000.) as i32;
    let n_index = (*y / 1000.) as i32;

    // eastings and northings of the south-west corner of the cell
    let x0 = e_index as i32 * 1000;
    let y0 = n_index as i32 * 1000;

    // The easting, northing and geoid shifts for the four corners of the cell
    // any of these could be Err, so use try!

    // bottom-left grid intersection
    let s0: (f64, f64, f64) = try!(get_ostn_ref(&(e_index), &(n_index)));
    // bottom-right
    let s1: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 0)));
    // top-left
    let s2: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 0), &(n_index + 1)));
    // top-right
    let s3: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 1)));

    // offset within square
    let dx = x - (x0 as f64);
    let dy = y - (y0 as f64);

    let t = dx / 1000.;
    let u = dy / 1000.;

    let f0 = (1. - t as f64) * (1. - u as f64);
    let f1 = t as f64 * (1. - u as f64);
    let f2 = (1. - t as f64) * u as f64;
    let f3 = t as f64 * u as f64;

    // bilinear interpolation, to obtain the actual shifts
    let se = f0 * s0.0 + f1 * s1.0 + f2 * s2.0 + f3 * s3.0;
    let sn = f0 * s0.1 + f1 * s1.1 + f2 * s2.1 + f3 * s3.1;
    let sg = f0 * s0.2 + f1 * s1.2 + f2 * s2.2 + f3 * s3.2;

    Ok((se.round_to_mm(), sn.round_to_mm(), sg.round_to_mm()))

}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    // original coordinates are 651307.003, 313255.686
    fn test_ostn_hashmap_retrieval() {
        let eastings = 651;
        let northings = 313;
        let expected = (102.775, -78.244, 44.252);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_failed_ostn_hashmap_retrieval() {
        // we're try!ing this in the shift calculation function, so an Err is fine
        let eastings = 999;
        let northings = 999;
        let expected = (1., 1., 1.);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    fn test_ostn02_shift_incorporation() {
        // these are the input values and corrections on p20-21
        let eastings = 651307.003;
        let northings = 313255.686;
        let expected = (102.789, -78.238, 44.244);
        assert_eq!(expected, ostn02_shifts(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_min_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // below min_lon
        check(&-6.379881, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_min_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // below min lat
        check(&49.871158, (&min_lat, &max_lat)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // above max lon
        check(&1.768961, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // above max lat
        check(&55.811742, (&min_lat, &max_lat)).unwrap();
    }
}
<commit_msg>Document ToMm trait<commit_after>#![doc(html_root_url = "https://urschrei.github.io/lonlat_bng/")]
//! This module provides utilities to the conversions module
use conversions::MIN_X_SHIFT;
use conversions::MIN_Y_SHIFT;
use conversions::MIN_Z_SHIFT;

use std;
use std::fmt;
use ostn02_phf::ostn02_lookup;
include!("hexkeys.rs");

// fn helmert(lon_vec: [&f64], lat_vec: [&f64]) -> (Vec<f64>, Vec<f64>) {
//     let t_array = Vec3::new(TX, TY, TZ);
//     let params = Mat3::new(1. + s, RZS, -RYS, -RZS, 1. + s, RXS, RYS, -RXS, 1. + s);
//     // let zeros: Vec<&f64> = vec![&1.; lon_vec.len()];
//     let test = vec![1, 2, 3, 4, 5, 6];
//     // let mut combined: Vec<&f64> = lon_vec.extend(lat_vec.iter()).collect();
//     // combined.extend(zeros.iter().cloned());
//     // let tmat = DMat::from_row_vec(3, zeros.len(), &combined);
//     let tmat = DMat::from_row_vec(3, 2, &test);
//     // build input vector of x, y, and z columns
//     // let inp = DMat::from_row_vec(3, 1, vec![lon_vec, lat_vec, h_vec]);
//     (vec![1.], vec![2.])
// }

/// Bounds checking for input values
pub fn check<T>(to_check: T, bounds: (T, T)) -> Result<T, ()>
    where T: std::cmp::PartialOrd + fmt::Display + Copy
{
    match to_check {
        to_check if bounds.0 <= to_check && to_check <= bounds.1 => Ok(to_check),
        _ => Err(()),
    }
}

/// Round an Easting or Northing coordinate to the nearest millimetre
pub trait ToMm {
    fn round_to_mm(self) -> f64;
}

impl ToMm for f64 {
    fn round_to_mm(self) -> f64 {
        (self * 1000.).round() as f64 / 1000.
    }
}

/// Round a float to eight decimal places
pub fn round_to_eight(x: f64, y: f64) -> (f64, f64) {
    let new_x = (x * 100000000.).round() as f64 / 100000000.;
    let new_y = (y * 100000000.).round() as f64 / 100000000.;
    (new_x, new_y)
}

/// Try to get OSTN02 shift parameters, and calculate offsets
pub fn get_ostn_ref(x: &i32, y: &i32) -> Result<(f64, f64, f64), ()> {
    // let key = format!("{:03x}{:03x}", y, x);
    // optimisation from https://github.com/hoodie/concatenation_benchmarks-rs
    let mut key = String::with_capacity(32);
    key.push_str(HEXKEYS.get(y).unwrap());
    key.push_str(HEXKEYS.get(x).unwrap());
    // Some or None, so convert to Result, which we can try!
    let result = try!(ostn02_lookup(&*key).ok_or(()));
    Ok((result.0 as f64 / 1000. + MIN_X_SHIFT,
        result.1 as f64 / 1000. + MIN_Y_SHIFT,
        result.2 as f64 / 1000. + MIN_Z_SHIFT))

}

// Input values must be valid ETRS89 grid references
// See p20 of the transformation user guide at
// https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html
/// Calculate OSTN02 shifts for a given coordinate
pub fn ostn02_shifts(x: &f64, y: &f64) -> Result<(f64, f64, f64), ()> {
    let e_index = (*x / 1000.) as i32;
    let n_index = (*y / 1000.) as i32;

    // eastings and northings of the south-west corner of the cell
    let x0 = e_index as i32 * 1000;
    let y0 = n_index as i32 * 1000;

    // The easting, northing and geoid shifts for the four corners of the cell
    // any of these could be Err, so use try!

    // bottom-left grid intersection
    let s0: (f64, f64, f64) = try!(get_ostn_ref(&(e_index), &(n_index)));
    // bottom-right
    let s1: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 0)));
    // top-left
    let s2: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 0), &(n_index + 1)));
    // top-right
    let s3: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 1)));

    // offset within square
    let dx = x - (x0 as f64);
    let dy = y - (y0 as f64);

    let t = dx / 1000.;
    let u = dy / 1000.;

    let f0 = (1. - t as f64) * (1. - u as f64);
    let f1 = t as f64 * (1. - u as f64);
    let f2 = (1. - t as f64) * u as f64;
    let f3 = t as f64 * u as f64;

    // bilinear interpolation, to obtain the actual shifts
    let se = f0 * s0.0 + f1 * s1.0 + f2 * s2.0 + f3 * s3.0;
    let sn = f0 * s0.1 + f1 * s1.1 + f2 * s2.1 + f3 * s3.1;
    let sg = f0 * s0.2 + f1 * s1.2 + f2 * s2.2 + f3 * s3.2;

    Ok((se.round_to_mm(), sn.round_to_mm(), sg.round_to_mm()))

}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    // original coordinates are 651307.003, 313255.686
    fn test_ostn_hashmap_retrieval() {
        let eastings = 651;
        let northings = 313;
        let expected = (102.775, -78.244, 44.252);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_failed_ostn_hashmap_retrieval() {
        // we're try!ing this in the shift calculation function, so an Err is fine
        let eastings = 999;
        let northings = 999;
        let expected = (1., 1., 1.);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    fn test_ostn02_shift_incorporation() {
        // these are the input values and corrections on p20-21
        let eastings = 651307.003;
        let northings = 313255.686;
        let expected = (102.789, -78.238, 44.244);
        assert_eq!(expected, ostn02_shifts(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_min_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // below min_lon
        check(&-6.379881, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_min_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // below min lat
        check(&49.871158, (&min_lat, &max_lat)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // above max lon
        check(&1.768961, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // above max lat
        check(&55.811742, (&min_lat, &max_lat)).unwrap();
    }
}
<|endoftext|>


<commit_before>//! Internal module providing handy function

use encoding_rs::{self, Encoding};

/// Converts a &[u8] into a &[u32]
pub fn to_u32(s: &[u8]) -> &[u32] {
    assert!(s.len() % 4 == 0);
    unsafe { ::std::slice::from_raw_parts(s as *const [u8] as *const u32, s.len() / 4) }
}
pub fn read_slice<T>(s: &[u8]) -> T {
    unsafe { ::std::ptr::read(&s[..::std::mem::size_of::<T>()] as *const [u8] as *const T) }
}

pub fn read_u32(s: &[u8]) -> u32 {
    read_slice(s)
}

pub fn read_u16(s: &[u8]) -> u16 {
    read_slice(s)
}

pub fn read_usize(s: &[u8]) -> usize {
    read_u32(s) as usize
}

/// Returns an encoding from Windows code page number.
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756%28v=vs.85%29.aspx
/// Sometimes it can return a *superset* of the requested encoding, e.g. for several CJK encodings.
///
/// The code is copied from [rust-encoding](https://github.com/lifthrasiir/rust-encoding)
pub fn encoding_from_windows_code_page(cp: usize) -> Option<&'static Encoding> {
    match cp {
        65001 => Some(encoding_rs::UTF_8),
        866 => Some(encoding_rs::IBM866),
        28592 => Some(encoding_rs::ISO_8859_2),
        28593 => Some(encoding_rs::ISO_8859_3),
        28594 => Some(encoding_rs::ISO_8859_4),
        28595 => Some(encoding_rs::ISO_8859_5),
        28596 => Some(encoding_rs::ISO_8859_6),
        28597 => Some(encoding_rs::ISO_8859_7),
        28598 => Some(encoding_rs::ISO_8859_8),
        28603 => Some(encoding_rs::ISO_8859_13),
        28605 => Some(encoding_rs::ISO_8859_15),
        20866 => Some(encoding_rs::KOI8_R),
        21866 => Some(encoding_rs::KOI8_U),
        10000 => Some(encoding_rs::MACINTOSH),
        874 => Some(encoding_rs::WINDOWS_874),
        1250 => Some(encoding_rs::WINDOWS_1250),
        1251 => Some(encoding_rs::WINDOWS_1251),
        1252 => Some(encoding_rs::WINDOWS_1252),
        1253 => Some(encoding_rs::WINDOWS_1253),
        1254 => Some(encoding_rs::WINDOWS_1254),
        1255 => Some(encoding_rs::WINDOWS_1255),
        1256 => Some(encoding_rs::WINDOWS_1256),
        1257 => Some(encoding_rs::WINDOWS_1257),
        1258 => Some(encoding_rs::WINDOWS_1258),
        1259 | 10007 => Some(encoding_rs::X_MAC_CYRILLIC),
        936 | 54936 => Some(encoding_rs::GB18030), // XXX technicencoding_rsy wrong
        950 => Some(encoding_rs::BIG5),
        20932 => Some(encoding_rs::EUC_JP),
        50220 => Some(encoding_rs::ISO_2022_JP),
        932 => Some(encoding_rs::SHIFT_JIS),
        1201 => Some(encoding_rs::UTF_16BE),
        1200 => Some(encoding_rs::UTF_16LE),
        949 => Some(encoding_rs::EUC_KR),
        // Not available because not in the Encoding Standard
        //28591 => Some(encoding_rs::ISO_8859_1),
        //38598 => Some(encoding_rs::whatwg::ISO_8859_8_I),
        //52936 => Some(encoding_rs::HZ),
        _ => None,
    }
}

/// Push literal column into a String buffer
pub fn push_column(mut col: u32, buf: &mut String) {
    if col < 26 {
        buf.push((b'A' + col as u8) as char);
    } else {
        let mut rev = String::new();
        while col >= 26 {
            let c = col % 26;
            rev.push((b'A' + c as u8) as char);
            col -= c;
            col /= 26;
        }
        buf.extend(rev.chars().rev());
    }
}
<commit_msg>treat codepage 21010 as codepage 1200 (#86)<commit_after>//! Internal module providing handy function

use encoding_rs::{self, Encoding};

/// Converts a &[u8] into a &[u32]
pub fn to_u32(s: &[u8]) -> &[u32] {
    assert!(s.len() % 4 == 0);
    unsafe { ::std::slice::from_raw_parts(s as *const [u8] as *const u32, s.len() / 4) }
}
pub fn read_slice<T>(s: &[u8]) -> T {
    unsafe { ::std::ptr::read(&s[..::std::mem::size_of::<T>()] as *const [u8] as *const T) }
}

pub fn read_u32(s: &[u8]) -> u32 {
    read_slice(s)
}

pub fn read_u16(s: &[u8]) -> u16 {
    read_slice(s)
}

pub fn read_usize(s: &[u8]) -> usize {
    read_u32(s) as usize
}

/// Returns an encoding from Windows code page number.
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756%28v=vs.85%29.aspx
/// Sometimes it can return a *superset* of the requested encoding, e.g. for several CJK encodings.
///
/// The code is copied from [rust-encoding](https://github.com/lifthrasiir/rust-encoding)
pub fn encoding_from_windows_code_page(cp: usize) -> Option<&'static Encoding> {
    match cp {
        65001 => Some(encoding_rs::UTF_8),
        866 => Some(encoding_rs::IBM866),
        28592 => Some(encoding_rs::ISO_8859_2),
        28593 => Some(encoding_rs::ISO_8859_3),
        28594 => Some(encoding_rs::ISO_8859_4),
        28595 => Some(encoding_rs::ISO_8859_5),
        28596 => Some(encoding_rs::ISO_8859_6),
        28597 => Some(encoding_rs::ISO_8859_7),
        28598 => Some(encoding_rs::ISO_8859_8),
        28603 => Some(encoding_rs::ISO_8859_13),
        28605 => Some(encoding_rs::ISO_8859_15),
        20866 => Some(encoding_rs::KOI8_R),
        21866 => Some(encoding_rs::KOI8_U),
        10000 => Some(encoding_rs::MACINTOSH),
        874 => Some(encoding_rs::WINDOWS_874),
        1250 => Some(encoding_rs::WINDOWS_1250),
        1251 => Some(encoding_rs::WINDOWS_1251),
        1252 => Some(encoding_rs::WINDOWS_1252),
        1253 => Some(encoding_rs::WINDOWS_1253),
        1254 => Some(encoding_rs::WINDOWS_1254),
        1255 => Some(encoding_rs::WINDOWS_1255),
        1256 => Some(encoding_rs::WINDOWS_1256),
        1257 => Some(encoding_rs::WINDOWS_1257),
        1258 => Some(encoding_rs::WINDOWS_1258),
        1259 | 10007 => Some(encoding_rs::X_MAC_CYRILLIC),
        936 | 54936 => Some(encoding_rs::GB18030), // XXX technicencoding_rsy wrong
        950 => Some(encoding_rs::BIG5),
        20932 => Some(encoding_rs::EUC_JP),
        50220 => Some(encoding_rs::ISO_2022_JP),
        932 => Some(encoding_rs::SHIFT_JIS),
        1201 => Some(encoding_rs::UTF_16BE),
        1200 => Some(encoding_rs::UTF_16LE),
        949 => Some(encoding_rs::EUC_KR),
        // This is actually not a valid codepage but it happens with some unknown writer
        // Looking on internet, it looks like excel treats this as codepage 1200
        21010 => Some(encoding_rs::UTF_16LE),
        // Not available because not in the Encoding Standard
        //28591 => Some(encoding_rs::ISO_8859_1),
        //38598 => Some(encoding_rs::whatwg::ISO_8859_8_I),
        //52936 => Some(encoding_rs::HZ),
        _ => None,
    }
}

/// Push literal column into a String buffer
pub fn push_column(mut col: u32, buf: &mut String) {
    if col < 26 {
        buf.push((b'A' + col as u8) as char);
    } else {
        let mut rev = String::new();
        while col >= 26 {
            let c = col % 26;
            rev.push((b'A' + c as u8) as char);
            col -= c;
            col /= 26;
        }
        buf.extend(rev.chars().rev());
    }
}
<|endoftext|>