<commit_before>#[derive(Debug)]
#[allow(non_camel_case_types)]
#[allow(dead_code)] // TODO remove
pub enum Instruction {
    ALOAD(Type),
    ASTORE(Type),
    LOAD(Type, LocalVarRef),
    STORE(Type, LocalVarRef),

    ARRAYLENGTH,

    ATHROW,

    CHECKCAST(ConstPoolRef),
    INSTANCEOF(ConstPoolRef),

    ANEWARRAY(ConstPoolRef),
    MULTIANEWARRAY(ConstPoolRef, u8),
    NEW(ConstPoolRef),
    NEWARRAY(Type),

    // D2F, D2I,...
    CONVERT(Type, Type),

    ADD(Type),
    DIV(Type),
    MUL(Type),
    NEG(Type),
    REM(Type),
    SUB(Type),
    RETURN(Option<Type>),

    IINC(LocalVarRef, i16),

    AND(Type),
    OR(Type),
    SHL(Type),
    SHR(Type),
    USHR(Type),
    XOR(Type),

    DCMPG,
    DCMPL,
    FCMPG,
    FCMPL,
    LCMP,

    ACONST_NULL,
    DCONST_0,
    DCONST_1,
    FCONST_0,
    FCONST_1,
    FCONST_2,
    LCONST_0,
    LCONST_1,
    BIPUSH(i8),
    SIPUSH(i16),
    LDC(ConstPoolRef),
    LDC2_W(ConstPoolRef),

    DUP,
    DUP_X1,
    DUP_X2,
    DUP2,
    DUP2_X1,
    DUP2_X2,
    POP,
    POP2,
    SWAP,

    GETFIELD(ConstPoolRef),
    GETSTATIC(ConstPoolRef),
    PUTFIELD(ConstPoolRef),
    PUTSTATIC(ConstPoolRef),

    GOTO(i32),
    JSR(i32),
    RET(LocalVarRef),

    IF_ACMP(ComparisonEqual, i16),
    IF_ICMP(Comparison, i16),
    // comparison with zero
    IF(Comparison, i16),
    IFNULL(ComparisonEqual, i16),

    INVOKEINTERFACE(ConstPoolRef, u8),
    INVOKESPECIAL(ConstPoolRef),
    INVOKESTATIC(ConstPoolRef),
    INVOKEVIRTUAL(ConstPoolRef),

    LOOKUPSWITCH(i32, i32, Vec<(i32, i32)>),
    TABLESWITCH(i32, i32, i32, Vec<i32>),

    MONITORENTER,
    MONITOREXIT,

    NOP,
}

// index into the constant pool
pub type ConstPoolRef = u16;

// index into the local variables
pub type LocalVarRef = u16;

// true: equals, false: not equals
pub type ComparisonEqual = bool;

#[derive(Debug)]
pub enum Type {
    Reference,
    Char,
    Byte,
    Short,
    Int,
    Long,
    Float,
    Double,
}

#[derive(Debug)]
pub enum Comparison {
    EQ,
    GE,
    GT,
    LE,
    LT,
    NE,
}

impl Instruction {
    pub fn decode(bytes: &[u8]) -> Result<Vec<Instruction>, String> {
        use self::Instruction::*;
        use self::Type::*;
        use self::Comparison::*;
        fn next(index: &mut usize, bytes: &[u8]) -> Result<u8, String> {
            if *index >= bytes.len() {
                return Err("incomplete instruction".to_owned());
            }
            *index += 1;
            Ok(bytes[*index - 1])
        }
        fn next_u16(index: &mut usize, bytes: &[u8]) -> Result<u16, String> {
            let b1 = next(index, bytes)? as u16;
            let b2 = next(index, bytes)? as u16;
            return Ok((b1 << 8) | b2);
        }

        let mut vec = Vec::new();

        let mut index = 0;
        while index < bytes.len() {
            let cur = bytes[index];
            index += 1;
            vec.push(match cur {
                0x32 => ALOAD(Reference),
                0x53 => ASTORE(Reference),
                0x01 => ACONST_NULL,
                0x19 => LOAD(Reference, next(&mut index, bytes)? as u16),
                0x2a => LOAD(Reference, 0),
                0x2b => LOAD(Reference, 1),
                0x2c => LOAD(Reference, 2),
                0x2d => LOAD(Reference, 3),
                0xbd => ANEWARRAY(next_u16(&mut index, bytes)?),
                0xb0 => RETURN(Some(Reference)),
                0xbe => ARRAYLENGTH,
                0x3a => STORE(Reference, next(&mut index, bytes)? as u16),
                0x4b => STORE(Reference, 0),
                0x4c => STORE(Reference, 1),
                0x4d => STORE(Reference, 2),
                0x4e => STORE(Reference, 3),
                0xbf => ATHROW,
                0x33 => ALOAD(Byte),
                0x54 => ASTORE(Byte),
                0x10 => BIPUSH(next(&mut index, bytes)? as i8),
                0x34 => ALOAD(Char),
                0x55 => ASTORE(Char),
                0xc0 => CHECKCAST(next_u16(&mut index, bytes)?),
                0x90 => CONVERT(Double, Float),
                0x8e => CONVERT(Double, Int),
                0x8f => CONVERT(Double, Long),
                0x63 => ADD(Double),
                0x31 => ALOAD(Double),
                0x52 => ASTORE(Double),
                0x98 => DCMPG,
                0x97 => DCMPL,
                0x0e => DCONST_0,
                0x0f => DCONST_1,
                0x6f => DIV(Double),
                0x18 => LOAD(Double, next(&mut index, bytes)? as u16),
                0x26 => LOAD(Double, 0),
                0x27 => LOAD(Double, 1),
                0x28 => LOAD(Double, 2),
                0x29 => LOAD(Double, 3),
                0x6b => MUL(Double),
                0x77 => NEG(Double),
                0x73 => REM(Double),
                0xaf => RETURN(Some(Double)),
                0x39 => STORE(Double, next(&mut index, bytes)? as u16),
                0x47 => STORE(Double, 0),
                0x48 => STORE(Double, 1),
                0x49 => STORE(Double, 2),
                0x4a => STORE(Double, 3),
                0x67 => SUB(Double),
                0x59 => DUP,
                0x5a => DUP_X1,
                0x5b => DUP_X2,
                0x5c => DUP2,
                0x5d => DUP2_X1,
                0x5e => DUP2_X2,
                0x8d => CONVERT(Float, Double),
                0x8b => CONVERT(Float, Int),
                0x8c => CONVERT(Float, Long),
                0x62 => ADD(Float),
                0x30 => ALOAD(Float),
                0x51 => ASTORE(Float),
                0x96 => FCMPG,
                0x95 => FCMPL,
                0x0b => FCONST_0,
                0x0c => FCONST_1,
                0x0d => FCONST_2,
                0x6e => fdiv,
                0x17 => fload,
                0x22 => fload_0,
                0x23 => fload_1,
                0x24 => fload_2,
                0x25 => fload_3,
                // 0x6a => fmul,
                // 0x76 => fneg,
                // 0x72 => frem,
                // 0xae => freturn,
                // 0x38 => fstore,
                // 0x43 => fstore_0,
                // 0x44 => fstore_1,
                // 0x45 => fstore_2,
                // 0x46 => fstore_3,
                // 0x66 => fsub,
                // 0xb4 => getfield,
                // 0xb2 => getstatic,
                // 0xa7 => goto,
                // 0xc8 => goto_w,
                // 0x91 => i2b,
                // 0x92 => i2c,
                // 0x87 => i2d,
                // 0x86 => i2f,
                // 0x85 => i2l,
                // 0x93 => i2s,
                // 0x60 => iadd,
                // 0x2e => iaload,
                // 0x7e => iand,
                // 0x4f => iastore,
                // 0x02 => iconst_m1,
                // 0x03 => iconst_0,
                // 0x04 => iconst_1,
                // 0x05 => iconst_2,
                // 0x06 => iconst_3,
                // 0x07 => iconst_4,
                // 0x08 => iconst_5,
                // 0x6c => idiv,
                // 0xa5 => if_acmpeq,
                // 0xa6 => if_acmpne,
                // 0x9f => if_icmpeq,
                // 0xa2 => if_icmpge,
                // 0xa3 => if_icmpgt,
                // 0xa4 => if_icmple,
                // 0xa1 => if_icmplt,
                // 0xa0 => if_icmpne,
                // 0x99 => ifeq,
                // 0x9c => ifge,
                // 0x9d => ifgt,
                // 0x9e => ifle,
                // 0x9b => iflt,
                // 0x9a => ifne,
                // 0xc7 => ifnonnull,
                // 0xc6 => ifnull,
                // 0x84 => iinc,
                // 0x15 => iload,
                // 0x1a => iload_0,
                // 0x1b => iload_1,
                // 0x1c => iload_2,
                // 0x1d => iload_3,
                // 0xfe => impdep1,
                // 0xff => impdep2,
                // 0x68 => imul,
                // 0x74 => ineg,
                // 0xc1 => instanceof,
                // 0xba => invokedynamic,
                // 0xb9 => invokeinterface,
                // 0xb7 => invokespecial,
                // 0xb8 => invokestatic,
                // 0xb6 => invokevirtual,
                // 0x80 => ior,
                // 0x70 => irem,
                // 0xac => ireturn,
                // 0x78 => ishl,
                // 0x7a => ishr,
                // 0x36 => istore,
                // 0x3b => istore_0,
                // 0x3c => istore_1,
                // 0x3d => istore_2,
                // 0x3e => istore_3,
                // 0x64 => isub,
                // 0x7c => iushr,
                // 0x82 => ixor,
                // 0xa8 => jsr,
                // 0xc9 => jsr_w,
                // 0x8a => l2d,
                // 0x89 => l2f,
                // 0x88 => l2i,
                // 0x61 => ladd,
                // 0x2f => laload,
                // 0x7f => land,
                // 0x50 => lastore,
                // 0x94 => lcmp,
                // 0x09 => lconst_0,
                // 0x0a => lconst_1,
                // 0x12 => ldc,
                // 0x13 => ldc_w,
                // 0x14 => ldc2_w,
                // 0x6d => ldiv,
                // 0x16 => lload,
                // 0x1e => lload_0,
                // 0x1f => lload_1,
                // 0x20 => lload_2,
                // 0x21 => lload_3,
                // 0x69 => lmul,
                // 0x75 => lneg,
                // 0xab => lookupswitch,
                // 0x81 => lor,
                // 0x71 => lrem,
                // 0xad => lreturn,
                // 0x79 => lshl,
                // 0x7b => lshr,
                // 0x37 => lstore,
                // 0x3f => lstore_0,
                // 0x40 => lstore_1,
                // 0x41 => lstore_2,
                // 0x42 => lstore_3,
                // 0x65 => lsub,
                // 0x7d => lushr,
                // 0x83 => lxor,
                // 0xc2 => monitorenter,
                // 0xc3 => monitorexit,
                // 0xc5 => multianewarray,
                // 0xbb => new,
                // 0xbc => newarray,
                // 0x00 => nop,
                // 0x57 => pop,
                // 0x58 => pop2,
                // 0xb5 => putfield,
                // 0xb3 => putstatic,
                // 0xa9 => ret,
                // 0xb1 => return,
                // 0x35 => saload,
                // 0x56 => sastore,
                // 0x11 => sipush,
                // 0x5f => swap,
                // 0xaa => tableswitch,
                // 0xc4 => wide,
                op@_ => return Err(format!("Unknown Instruction {:#x}", op)),
            });
        }

        // TODO: gotos/if anpassen
        return Ok(vec);
    }
}
<commit_msg>decoded most instructions<commit_after>#[derive(Debug)]
#[allow(non_camel_case_types)]
#[allow(dead_code)] // TODO remove
pub enum Instruction {
    ALOAD(Type),
    ASTORE(Type),
    LOAD(Type, LocalVarRef),
    STORE(Type, LocalVarRef),

    ARRAYLENGTH,

    ATHROW,

    CHECKCAST(ConstPoolRef),
    INSTANCEOF(ConstPoolRef),

    ANEWARRAY(ConstPoolRef),
    MULTIANEWARRAY(ConstPoolRef, u8),
    NEW(ConstPoolRef),
    NEWARRAY(Type),

    // D2F, D2I,...
    CONVERT(Type, Type),

    ADD(Type),
    DIV(Type),
    MUL(Type),
    NEG(Type),
    REM(Type),
    SUB(Type),
    RETURN(Option<Type>),

    IINC(LocalVarRef, i16),

    AND(Type),
    OR(Type),
    SHL(Type),
    SHR(Type),
    USHR(Type),
    XOR(Type),

    DCMPG,
    DCMPL,
    FCMPG,
    FCMPL,
    LCMP,

    ACONST_NULL,
    DCONST_0,
    DCONST_1,
    FCONST_0,
    FCONST_1,
    FCONST_2,
    LCONST_0,
    LCONST_1,
    BIPUSH(i8),
    SIPUSH(i16),
    LDC(ConstPoolRef),
    LDC2_W(ConstPoolRef),

    DUP,
    DUP_X1,
    DUP_X2,
    DUP2,
    DUP2_X1,
    DUP2_X2,
    POP,
    POP2,
    SWAP,

    GETFIELD(ConstPoolRef),
    GETSTATIC(ConstPoolRef),
    PUTFIELD(ConstPoolRef),
    PUTSTATIC(ConstPoolRef),

    GOTO(i32),
    JSR(i32),
    RET(LocalVarRef),

    IF_ACMP(ComparisonEqual, i16),
    IF_ICMP(Comparison, i16),
    // comparison with zero
    IF(Comparison, i16),
    IFNULL(ComparisonEqual, i16),

    INVOKEINTERFACE(ConstPoolRef, u8),
    INVOKESPECIAL(ConstPoolRef),
    INVOKESTATIC(ConstPoolRef),
    INVOKEVIRTUAL(ConstPoolRef),

    LOOKUPSWITCH(i32, i32, Vec<(i32, i32)>),
    TABLESWITCH(i32, i32, i32, Vec<i32>),

    MONITORENTER,
    MONITOREXIT,

    NOP,
}

// index into the constant pool
pub type ConstPoolRef = u16;

// index into the local variables
pub type LocalVarRef = u16;

// true: equals, false: not equals
pub type ComparisonEqual = bool;

#[derive(Debug)]
pub enum Type {
    Reference,
    Char,
    Boolean,
    Byte,
    Short,
    Int,
    Long,
    Float,
    Double,
}

#[derive(Debug)]
pub enum Comparison {
    EQ,
    GE,
    GT,
    LE,
    LT,
    NE,
}

impl Instruction {
    pub fn decode(bytes: &[u8]) -> Result<Vec<Instruction>, String> {
        use self::Instruction::*;
        use self::Type::*;
        use self::Comparison::*;
        fn next(index: &mut usize, bytes: &[u8]) -> Result<u8, String> {
            if *index >= bytes.len() {
                return Err("incomplete instruction".to_owned());
            }
            *index += 1;
            Ok(bytes[*index - 1])
        }
        fn next_u16(index: &mut usize, bytes: &[u8]) -> Result<u16, String> {
            let b1 = next(index, bytes)? as u16;
            let b2 = next(index, bytes)? as u16;
            return Ok((b1 << 8) | b2);
        }
        fn next_u32(index: &mut usize, bytes: &[u8]) -> Result<u32, String> {
            let b1 = next_u16(index, bytes)? as u32;
            let b2 = next_u16(index, bytes)? as u32;
            return Ok((b1 << 16) | b2);
        }

        let mut vec = Vec::new();

        let mut index = 0;
        while index < bytes.len() {
            let cur = bytes[index];
            index += 1;
            vec.push(match cur {
                0x32 => ALOAD(Reference),
                0x53 => ASTORE(Reference),
                0x01 => ACONST_NULL,
                0x19 => LOAD(Reference, next(&mut index, bytes)? as u16),
                0x2a => LOAD(Reference, 0),
                0x2b => LOAD(Reference, 1),
                0x2c => LOAD(Reference, 2),
                0x2d => LOAD(Reference, 3),
                0xbd => ANEWARRAY(next_u16(&mut index, bytes)?),
                0xb0 => RETURN(Some(Reference)),
                0xbe => ARRAYLENGTH,
                0x3a => STORE(Reference, next(&mut index, bytes)? as u16),
                0x4b => STORE(Reference, 0),
                0x4c => STORE(Reference, 1),
                0x4d => STORE(Reference, 2),
                0x4e => STORE(Reference, 3),
                0xbf => ATHROW,
                0x33 => ALOAD(Byte),
                0x54 => ASTORE(Byte),
                0x10 => BIPUSH(next(&mut index, bytes)? as i8),
                0x34 => ALOAD(Char),
                0x55 => ASTORE(Char),
                0xc0 => CHECKCAST(next_u16(&mut index, bytes)?),
                0x90 => CONVERT(Double, Float),
                0x8e => CONVERT(Double, Int),
                0x8f => CONVERT(Double, Long),
                0x63 => ADD(Double),
                0x31 => ALOAD(Double),
                0x52 => ASTORE(Double),
                0x98 => DCMPG,
                0x97 => DCMPL,
                0x0e => DCONST_0,
                0x0f => DCONST_1,
                0x6f => DIV(Double),
                0x18 => LOAD(Double, next(&mut index, bytes)? as u16),
                0x26 => LOAD(Double, 0),
                0x27 => LOAD(Double, 1),
                0x28 => LOAD(Double, 2),
                0x29 => LOAD(Double, 3),
                0x6b => MUL(Double),
                0x77 => NEG(Double),
                0x73 => REM(Double),
                0xaf => RETURN(Some(Double)),
                0x39 => STORE(Double, next(&mut index, bytes)? as u16),
                0x47 => STORE(Double, 0),
                0x48 => STORE(Double, 1),
                0x49 => STORE(Double, 2),
                0x4a => STORE(Double, 3),
                0x67 => SUB(Double),
                0x59 => DUP,
                0x5a => DUP_X1,
                0x5b => DUP_X2,
                0x5c => DUP2,
                0x5d => DUP2_X1,
                0x5e => DUP2_X2,
                0x8d => CONVERT(Float, Double),
                0x8b => CONVERT(Float, Int),
                0x8c => CONVERT(Float, Long),
                0x62 => ADD(Float),
                0x30 => ALOAD(Float),
                0x51 => ASTORE(Float),
                0x96 => FCMPG,
                0x95 => FCMPL,
                0x0b => FCONST_0,
                0x0c => FCONST_1,
                0x0d => FCONST_2,
                0x6e => DIV(Float),
                0x17 => LOAD(Float, next(&mut index, bytes)? as u16),
                0x22 => LOAD(Float, 0),
                0x23 => LOAD(Float, 1),
                0x24 => LOAD(Float, 2),
                0x25 => LOAD(Float, 3),
                0x6a => MUL(Float),
                0x76 => NEG(Float),
                0x72 => REM(Float),
                0xae => RETURN(Some(Float)),
                0x38 => STORE(Float, next(&mut index, bytes)? as u16),
                0x43 => STORE(Float, 0),
                0x44 => STORE(Float, 1),
                0x45 => STORE(Float, 2),
                0x46 => STORE(Float, 3),
                0x66 => SUB(Float),
                0xb4 => GETFIELD(next_u16(&mut index, bytes)?),
                0xb2 => GETSTATIC(next_u16(&mut index, bytes)?),
                0xa7 => GOTO((next_u16(&mut index, bytes)? as i16) as i32),
                0xc8 => GOTO(next_u32(&mut index, bytes)? as i32),
                0x91 => CONVERT(Int, Byte),
                0x92 => CONVERT(Int, Char),
                0x87 => CONVERT(Int, Double),
                0x86 => CONVERT(Int, Float),
                0x85 => CONVERT(Int, Long),
                0x93 => CONVERT(Int, Short),
                0x60 => ADD(Int),
                0x2e => ALOAD(Int),
                0x7e => AND(Int),
                0x4f => ASTORE(Int),
                0x03 => BIPUSH(0),
                0x02 => BIPUSH(-1),
                0x04 => BIPUSH(1),
                0x05 => BIPUSH(2),
                0x06 => BIPUSH(3),
                0x07 => BIPUSH(4),
                0x08 => BIPUSH(5),
                0x6c => DIV(Int),
                0xa5 => IF_ACMP(true, next_u16(&mut index, bytes)? as i16),
                0xa6 => IF_ACMP(false, next_u16(&mut index, bytes)? as i16),
                0x9f => IF_ICMP(EQ, next_u16(&mut index, bytes)? as i16),
                0xa2 => IF_ICMP(GE, next_u16(&mut index, bytes)? as i16),
                0xa3 => IF_ICMP(GT, next_u16(&mut index, bytes)? as i16),
                0xa4 => IF_ICMP(LE, next_u16(&mut index, bytes)? as i16),
                0xa1 => IF_ICMP(LT, next_u16(&mut index, bytes)? as i16),
                0xa0 => IF_ICMP(NE, next_u16(&mut index, bytes)? as i16),
                0x99 => IF(EQ, next_u16(&mut index, bytes)? as i16),
                0x9c => IF(GE, next_u16(&mut index, bytes)? as i16),
                0x9d => IF(GT, next_u16(&mut index, bytes)? as i16),
                0x9e => IF(LE, next_u16(&mut index, bytes)? as i16),
                0x9b => IF(LT, next_u16(&mut index, bytes)? as i16),
                0x9a => IF(NE, next_u16(&mut index, bytes)? as i16),
                0xc7 => IFNULL(false, next_u16(&mut index, bytes)? as i16),
                0xc6 => IFNULL(true, next_u16(&mut index, bytes)? as i16),
                0x84 => {
                    IINC(next(&mut index, bytes)? as u16,
                         (next(&mut index, bytes)? as i8) as i16)
                }
                0x15 => LOAD(Int, next(&mut index, bytes)? as u16),
                0x1a => LOAD(Int, 0),
                0x1b => LOAD(Int, 1),
                0x1c => LOAD(Int, 2),
                0x1d => LOAD(Int, 3),
                0x68 => MUL(Int),
                0x74 => NEG(Int),
                0xc1 => INSTANCEOF(next_u16(&mut index, bytes)?),
                0xb9 => {
                    let op = INVOKEINTERFACE(next_u16(&mut index, bytes)?,
                                             next(&mut index, bytes)?);
                    next(&mut index, bytes)?; // discard 0
                    op
                }
                0xb7 => INVOKESPECIAL(next_u16(&mut index, bytes)?),
                0xb8 => INVOKESTATIC(next_u16(&mut index, bytes)?),
                0xb6 => INVOKEVIRTUAL(next_u16(&mut index, bytes)?),
                0x80 => OR(Int),
                0x70 => REM(Int),
                0xac => RETURN(Some(Int)),
                0x78 => SHL(Int),
                0x7a => SHR(Int),
                0x36 => STORE(Int, next(&mut index, bytes)? as u16),
                0x3b => STORE(Int, 0),
                0x3c => STORE(Int, 1),
                0x3d => STORE(Int, 2),
                0x3e => STORE(Int, 3),
                0x64 => SUB(Int),
                0x7c => USHR(Int),
                0x82 => XOR(Int),
                0xa8 => JSR((next_u16(&mut index, bytes)? as i16) as i32),
                0xc9 => JSR(next_u32(&mut index, bytes)? as i32),
                0x8a => CONVERT(Long, Double),
                0x89 => CONVERT(Long, Float),
                0x88 => CONVERT(Long, Int),
                0x61 => ADD(Long),
                0x2f => ALOAD(Long),
                0x7f => AND(Long),
                0x50 => ASTORE(Long),
                0x94 => LCMP,
                0x09 => LCONST_0,
                0x0a => LCONST_1,
                0x12 => LDC(next(&mut index, bytes)? as u16),
                0x13 => LDC(next_u16(&mut index, bytes)?),
                0x14 => LDC2_W(next_u16(&mut index, bytes)?),
                0x6d => DIV(Long),
                0x16 => LOAD(Long, next(&mut index, bytes)? as u16),
                0x1e => LOAD(Long, 0),
                0x1f => LOAD(Long, 1),
                0x20 => LOAD(Long, 2),
                0x21 => LOAD(Long, 3),
                0x69 => MUL(Long),
                0x75 => NEG(Long),
                // 0xab => lookupswitch, // TODO
                0x81 => OR(Long),
                0x71 => REM(Long),
                0xad => RETURN(Some(Long)),
                0x79 => SHL(Long),
                0x7b => SHR(Long),
                0x37 => STORE(Long, next(&mut index, bytes)? as u16),
                0x3f => STORE(Long, 0),
                0x40 => STORE(Long, 1),
                0x41 => STORE(Long, 2),
                0x42 => STORE(Long, 3),
                0x65 => SUB(Long),
                0x7d => USHR(Long),
                0x83 => XOR(Long),
                0xc2 => MONITORENTER,
                0xc3 => MONITOREXIT,
                0xc5 => MULTIANEWARRAY(next_u16(&mut index, bytes)?, next(&mut index, bytes)?),
                0xbb => NEW(next_u16(&mut index, bytes)?),
                0xbc => {
                    NEWARRAY(match next(&mut index, bytes)? {
                        4 => Boolean,
                        5 => Char,
                        6 => Float,
                        7 => Double,
                        8 => Byte,
                        9 => Short,
                        10 => Int,
                        11 => Long,
                        c @ _ => return Err(format!("unknown array type: {}", c)),
                    })
                }
                0x00 => NOP,
                0x57 => POP,
                0x58 => POP2,
                0xb5 => PUTFIELD(next_u16(&mut index, bytes)?),
                0xb3 => PUTSTATIC(next_u16(&mut index, bytes)?),
                0xa9 => RET(next(&mut index, bytes)? as u16),
                0xb1 => RETURN(None),
                0x35 => ALOAD(Short),
                0x56 => ASTORE(Short),
                0x11 => SIPUSH(next_u16(&mut index, bytes)? as i16),
                0x5f => SWAP,
                // 0xaa => tableswitch, // TODO
                // 0xc4 => wide, // TODO
                op @ _ => return Err(format!("Unknown Instruction {:#x}", op)),
            });
        }

        // TODO: gotos/if anpassen
        return Ok(vec);
    }
}
<|endoftext|>


<commit_before>use pancurses::{Input, Window};
use errext::{ErrExt, PResult};
use command::run_expression;

fn print_buffer(screen: &Window, buffer: &str) -> PResult {
    let height = (screen.get_max_y() - 1) as usize;
    let width = screen.get_max_x() as usize;
    screen.mv(0, 0).as_err()?;
    for line in buffer.lines().take(height) {
        let max = ::std::cmp::min(width, line.len());
        screen.addstr(&line[..max]).as_err()?;
        screen.addch('\n').as_err()?;
    }
    Ok(())
}

fn print_command(screen: &Window, buffer: &str) -> PResult {
    let height = screen.get_max_y() - 1;
    let width = screen.get_max_x() - 1;
    screen.mv(height - 1, 0).as_err()?;
    screen.hline(0, width).as_err()?;
    screen.mv(height, 0).as_err()?;
    let max = ::std::cmp::min(width as usize, buffer.len());
    screen.addstr(&buffer[..max]).as_err()?;
    Ok(())
}

pub fn input_loop(screen: Window) -> PResult {
    let mut output_buffer = String::from("");
    let mut command_buffer = String::new();
    // let (mut x, mut y) = (0, 0);
    loop {
        screen.clear().as_err()?;
        print_buffer(&screen, &output_buffer)?;
        print_command(&screen, &command_buffer)?;
        screen.refresh().as_err()?;
        let next = screen.getch().unwrap();
        match next {
            Input::KeyBackspace |
            Input::Character('\x08') |
            Input::Character('\x7f') => {
                command_buffer.pop();
            }
            Input::Character('\n') => {
                output_buffer.push_str("$ ");
                let output = run_expression(&command_buffer)?;
                output_buffer.push_str(&output.command);
                output_buffer.push_str("\n");
                output_buffer.push_str(&output.interleaved);
                output_buffer.push_str("\n");
                command_buffer.clear();
            }
            Input::Character(chr) => {
                println!("char: {:?}", chr);
                command_buffer.push(chr);
            }
            _ => {}
        };
    }
}
<commit_msg>Make error handling panic at the site of the error<commit_after>use pancurses::{Input, Window};
use errext::{ErrExt, PResult};
use command::run_expression;

fn print_buffer(screen: &Window, buffer: &str) -> PResult {
    let height = (screen.get_max_y() - 1) as usize;
    let width = screen.get_max_x() as usize;
    screen.mv(0, 0).unwrap();
    for line in buffer.lines().take(height) {
        let max = ::std::cmp::min(width, line.len());
        screen.addstr(&line[..max]).unwrap();
        screen.addch('\n').unwrap();
    }
    Ok(())
}

fn print_command(screen: &Window, buffer: &str) -> PResult {
    let height = screen.get_max_y() - 1;
    let width = screen.get_max_x() - 1;
    screen.mv(height - 1, 0).unwrap();
    screen.hline(0, width).unwrap();
    screen.mv(height, 0).unwrap();
    let max = ::std::cmp::min(width as usize, buffer.len());
    screen.addstr(&buffer[..max]).unwrap();
    Ok(())
}

pub fn input_loop(screen: Window) -> PResult {
    let mut output_buffer = String::from("");
    let mut command_buffer = String::new();
    // let (mut x, mut y) = (0, 0);
    loop {
        screen.clear().unwrap();
        print_buffer(&screen, &output_buffer)?;
        print_command(&screen, &command_buffer)?;
        screen.refresh().unwrap();
        let next = screen.getch().unwrap();
        match next {
            Input::KeyBackspace |
            Input::Character('\x08') |
            Input::Character('\x7f') => {
                command_buffer.pop();
            }
            Input::Character('\n') => {
                output_buffer.push_str("$ ");
                let output = run_expression(&command_buffer)?;
                output_buffer.push_str(&output.command);
                output_buffer.push_str("\n");
                output_buffer.push_str(&output.interleaved);
                output_buffer.push_str("\n");
                command_buffer.clear();
            }
            Input::Character(chr) => {
                println!("char: {:?}", chr);
                command_buffer.push(chr);
            }
            _ => {}
        };
    }
}
<|endoftext|>


<commit_before>//! Serializes and deserializes Ardite Schema Definitions from different data
//! formats such as JSON and YAML.

use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::PathBuf;
use std::fs::File;
use linear_map::LinearMap;
use regex::Regex;
use serde_json;
use serde_yaml;
use error::{Error, ErrorCode};
use schema::{Definition, Type, Schema, SchemaType};
use value::Value;

/// Gets an Ardite Schema Definition from a file. Aims to support mainly the
/// JSON and YAML formats.
pub fn from_file(path: PathBuf) -> Result<Definition, Error> {
  let extension = path.extension().map_or("", |s| s.to_str().unwrap());
  let mut file = try!(File::open(&path));
  match extension {
    "json" => {
      let reader = BufReader::new(file);
      let data: SerdeDefinition = try!(serde_json::from_reader(reader));
      Ok(try!(data.into_definition()))
    },
    "yml" => {
      let mut string = String::new();
      try!(file.read_to_string(&mut string));
      let data: SerdeDefinition = try!(serde_yaml::from_str(&string));
      Ok(try!(data.into_definition()))
    },
    _ => Err(Error::new(
      ErrorCode::NotAcceptable,
      format!("File extension '{}' cannot be deserialized in '{}'.", extension, path.display()),
      Some("Use a recognizable file extension like '.json' or '.yml'.".to_owned())
    ))
  }
}

/// SchemaType used to deserialize data files into a usable definition type.
#[derive(Deserialize)]
struct SerdeDefinition {
  types: BTreeMap<String, SerdeSchema>
}

impl SerdeDefinition {
  /// Transforms the intermediary type into the useful type.
  fn into_definition(self) -> Result<Definition, Error> {
    Ok(Definition {
      types: {
        let mut types = LinearMap::new();
        for (key, value) in self.types.into_iter() {
          types.insert(key.to_owned(), Type { schema: try!(value.into_schema()) });
        }
        types
      }
    })
  }
}

/// Intermediary type used to deserialized data files into a usable schema
/// enum.
#[derive(Deserialize)]
struct SerdeSchema {
  #[serde(rename="type")]
  type_: Option<String>,
  #[serde(rename="multipleOf")]
  multiple_of: Option<f32>,
  minimum: Option<f64>,
  #[serde(rename="exclusiveMinimum")]
  exclusive_minimum: Option<bool>,
  maximum: Option<f64>,
  #[serde(rename="exclusiveMaximum")]
  exclusive_maximum: Option<bool>,
  #[serde(rename="minLength")]
  min_length: Option<u64>,
  #[serde(rename="maxLength")]
  max_length: Option<u64>,
  pattern: Option<String>,
  items: Option<Box<SerdeSchema>>,
  properties: Option<BTreeMap<String, SerdeSchema>>,
  required: Option<Vec<String>>,
  #[serde(rename="additionalProperties")]
  additional_properties: Option<bool>,
  #[serde(rename="enum")]
  enum_: Option<Vec<String>>
}

impl SerdeSchema {
  /// Transforms the intermediary type into the useful type.
  fn into_schema(self) -> Result<Schema, Error> {
    match self.type_ {
      Some(type_) => match type_.as_ref() {
        "null" => Ok(Schema {
          type_: SchemaType::Null
        }),
        "boolean" => Ok(Schema {
          type_: SchemaType::Boolean
        }),
        "number" | "integer" => Ok(Schema {
          type_: SchemaType::Number {
            multiple_of: self.multiple_of,
            minimum: self.minimum,
            exclusive_minimum: self.exclusive_minimum.unwrap_or(false),
            maximum: self.maximum,
            exclusive_maximum: self.exclusive_maximum.unwrap_or(false)
          }
        }),
        "string" => Ok(Schema {
          type_: SchemaType::String {
            min_length: self.min_length,
            max_length: self.max_length,
            pattern: self.pattern.map_or(None, |pattern| Regex::new(&pattern).ok())
          }
        }),
        "array" => {
          if let Some(items) = self.items {
            Ok(Schema {
              type_: SchemaType::Array {
                items: Box::new(try!(items.into_schema()))
              }
            })
          } else {
            Err(Error::validation("Missing `items` property for type 'array'.", "Add a schema at `items`."))
          }
        },
        "object" => Ok(Schema {
          type_: SchemaType::Object {
            required: self.required.unwrap_or(vec![]),
            additional_properties: self.additional_properties.unwrap_or(false),
            properties: {
              let mut map = LinearMap::new();
              for (key, definition) in self.properties.unwrap_or_default() {
                map.insert(key, try!(definition.into_schema()));
              }
              map
            }
          }
        }),
        _ => Err(Error::validation(
          format!("Invalid type '{}'.", type_),
          format!("Use a permitted type like 'string' and not '{}'.", type_)
        ))
      },
      None => {
        if let Some(enum_) = self.enum_ {
          Ok(Schema {
            type_: SchemaType::Enum(enum_.into_iter().map(Value::String).collect())
          })
        } else {
          Err(Error::validation("No schema type specified.", "Set a `type` property or an `enum` property."))
        }
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use super::from_file;
  use std::path::PathBuf;
  use schema::definition::create_basic;

  #[test]
  fn test_basic_json() {
    assert_eq!(from_file(PathBuf::from("tests/fixtures/definitions/basic.json")).unwrap(), create_basic());
  }

  #[test]
  fn test_basic_yaml() {
    assert_eq!(from_file(PathBuf::from("tests/fixtures/definitions/basic.yml")).unwrap(), create_basic());
  }
}
<commit_msg>feat: impl Into, and fix some warnings<commit_after>//! Serializes and deserializes Ardite Schema Definitions from different data
//! formats such as JSON and YAML.

use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::PathBuf;
use std::fs::File;
use linear_map::LinearMap;
use regex::Regex;
use serde_json;
use serde_yaml;
use error::{Error, ErrorCode};
use schema::{Definition, Type, Schema, SchemaType};
use value::Value;

/// Gets an Ardite Schema Definition from a file. Aims to support mainly the
/// JSON and YAML formats.
pub fn from_file(path: PathBuf) -> Result<Definition, Error> {
  let extension = path.extension().map_or("", |s| s.to_str().unwrap());
  let mut file = try!(File::open(&path));
  match extension {
    "json" => {
      let reader = BufReader::new(file);
      let data: SerdeDefinition = try!(serde_json::from_reader(reader));
      Ok(try!(data.into()))
    },
    "yml" => {
      let mut string = String::new();
      try!(file.read_to_string(&mut string));
      let data: SerdeDefinition = try!(serde_yaml::from_str(&string));
      Ok(try!(data.into()))
    },
    _ => Err(Error::new(
      ErrorCode::NotAcceptable,
      format!("File extension '{}' cannot be deserialized in '{}'.", extension, path.display()),
      Some("Use a recognizable file extension like '.json' or '.yml'.".to_owned())
    ))
  }
}

/// SchemaType used to deserialize data files into a usable definition type.
#[derive(Deserialize)]
struct SerdeDefinition {
  types: BTreeMap<String, SerdeSchema>
}

impl Into<Result<Definition, Error>> for SerdeDefinition {
  /// Transforms the intermediary type into the useful type.
  fn into(self) -> Result<Definition, Error> {
    Ok(Definition {
      types: {
        let mut types = LinearMap::new();
        for (key, value) in self.types.into_iter() {
          types.insert(key.to_owned(), Type { schema: try!(value.into()) });
        }
        types
      }
    })
  }
}

/// Intermediary type used to deserialized data files into a usable schema
/// enum.
#[derive(Deserialize)]
struct SerdeSchema {
  #[serde(rename="type")]
  type_: Option<String>,
  #[serde(rename="multipleOf")]
  multiple_of: Option<f32>,
  minimum: Option<f64>,
  #[serde(rename="exclusiveMinimum")]
  exclusive_minimum: Option<bool>,
  maximum: Option<f64>,
  #[serde(rename="exclusiveMaximum")]
  exclusive_maximum: Option<bool>,
  #[serde(rename="minLength")]
  min_length: Option<u64>,
  #[serde(rename="maxLength")]
  max_length: Option<u64>,
  pattern: Option<String>,
  items: Option<Box<SerdeSchema>>,
  properties: Option<BTreeMap<String, SerdeSchema>>,
  required: Option<Vec<String>>,
  #[serde(rename="additionalProperties")]
  additional_properties: Option<bool>,
  #[serde(rename="enum")]
  enum_: Option<Vec<String>>
}

impl Into<Result<Schema, Error>> for SerdeSchema {
  /// Transforms the intermediary type into the useful type.
  fn into(self) -> Result<Schema, Error> {
    match self.type_ {
      Some(type_) => match type_.as_ref() {
        "null" => Ok(Schema {
          type_: SchemaType::Null
        }),
        "boolean" => Ok(Schema {
          type_: SchemaType::Boolean
        }),
        "number" | "integer" => Ok(Schema {
          type_: SchemaType::Number {
            multiple_of: self.multiple_of,
            minimum: self.minimum,
            exclusive_minimum: self.exclusive_minimum.unwrap_or(false),
            maximum: self.maximum,
            exclusive_maximum: self.exclusive_maximum.unwrap_or(false)
          }
        }),
        "string" => Ok(Schema {
          type_: SchemaType::String {
            min_length: self.min_length,
            max_length: self.max_length,
            pattern: self.pattern.map_or(None, |pattern| Regex::new(&pattern).ok())
          }
        }),
        "array" => {
          if let Some(items) = self.items {
            Ok(Schema {
              type_: SchemaType::Array {
                items: Box::new(try!((*items).into()))
              }
            })
          } else {
            Err(Error::validation("Missing `items` property for type 'array'.", "Add a schema at `items`."))
          }
        },
        "object" => Ok(Schema {
          type_: SchemaType::Object {
            required: self.required.unwrap_or_else(|| vec![]),
            additional_properties: self.additional_properties.unwrap_or(false),
            properties: {
              let mut map = LinearMap::new();
              for (key, definition) in self.properties.unwrap_or_default() {
                map.insert(key, try!(definition.into()));
              }
              map
            }
          }
        }),
        _ => Err(Error::validation(
          format!("Invalid type '{}'.", type_),
          format!("Use a permitted type like 'string' and not '{}'.", type_)
        ))
      },
      None => {
        if let Some(enum_) = self.enum_ {
          Ok(Schema {
            type_: SchemaType::Enum(enum_.into_iter().map(Value::String).collect())
          })
        } else {
          Err(Error::validation("No schema type specified.", "Set a `type` property or an `enum` property."))
        }
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use super::from_file;
  use std::path::PathBuf;
  use schema::definition::create_basic;

  #[test]
  fn test_basic_json() {
    assert_eq!(from_file(PathBuf::from("tests/fixtures/definitions/basic.json")).unwrap(), create_basic());
  }

  #[test]
  fn test_basic_yaml() {
    assert_eq!(from_file(PathBuf::from("tests/fixtures/definitions/basic.yml")).unwrap(), create_basic());
  }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod test {
    use super::super::*;
    use sdl2::keyboard::Keycode;

    #[test]
    fn test_default()
    {
        let mut keypad = Keypad::default();
        // Ordered based on order in file
        let keys: [Keycode; 16] = [X, Num1, Num2, Num3, Q, W, E, A, S, D, Z, C, Num4, R, F, V];

        for i in 0..keys.len()
        {
            assert_eq!(keypad.pressed(i), false);
        }
    }

    #[test]
    fn test_pressing_keys()
    {
        let mut keypad = Keypad::default();
        // Ordered based on order in file
        let keys: [Keycode; 16] = [X, Num1, Num2, Num3, Q, W, E, A, S, D, Z, C, Num4, R, F, V];

        for i in 0..keys.len()
        {
            keypad.press(keys[i], true);
            assert!(keypad.pressed(i));

            keypad.press(keys[i], false);
            assert_eq!(keypad.pressed(i), false);
        }
    }
}<commit_msg>test private function<commit_after>#[cfg(test)]
mod test {
    use super::super::*;
    use sdl2::keyboard::Keycode;

    #[test]
    fn test_default()
    {
        let mut keypad = Keypad::default();
        // Ordered based on order in file
        let keys: [Keycode; 16] = [X, Num1, Num2, Num3, Q, W, E, A, S, D, Z, C, Num4, R, F, V];

        for i in 0..keys.len()
        {
            assert_eq!(keypad.pressed(i), false);
        }
    }

    #[test]
    fn test_pressing_keys()
    {
        let mut keypad = Keypad::default();
        // Ordered based on order in file
        let keys: [Keycode; 16] = [X, Num1, Num2, Num3, Q, W, E, A, S, D, Z, C, Num4, R, F, V];

        for i in 0..keys.len()
        {
            keypad.press(keys[i], true);
            assert!(keypad.pressed(i));

            keypad.press(keys[i], false);
            assert_eq!(keypad.pressed(i), false);
        }
    }

    #[test]
    fn test_set_key()
    {
        let mut keypad = Keypad::default();

        for i in 0..16 // Because I know then length of Keypad::keys()
        {
            keypad.set_key(i, true);
            assert!(keypad.pressed(i));

            keypad.set_key(i, false);
            assert_eq!(keypad.pressed(i), false);
        }
    }
}<|endoftext|>


<commit_before>// Copyright 2014-2016 Johannes Köster, Martin Larralde.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! One-way orf finder algorithm.
//!
//! Complexity: O(n).
//!
//! # Example
//!
//! ```
//! use bio::seq_analysis::orf::{Finder, Orf};
//! let start_codons = vec!(b"ATG");
//! let stop_codons  = vec!(b"TGA", b"TAG", b"TAA");
//! let min_len = 50;
//! let finder = Finder::new(start_codons, stop_codons, min_len);
//!
//! let sequence = b"ACGGCTAGAAAAGGCTAGAAAA";
//!
//! for Orf{start, end, offset} in finder.find_all(sequence) {
//!    let orf = &sequence[start..end];
//!    //...do something with orf sequence...
//! }
//! ```
//!
//! Right now the only way to check the reverse strand for orf is to use
//! the `alphabet::dna::RevComp` struct and to check for both sequences.
//! But that's not so performance friendly, as the reverse complementation and the orf research
//! could go on at the same time.

use std::borrow::Borrow;
use std::collections::VecDeque;
use std::iter;

/// An implementation of a naive algorithm finder
pub struct Finder {
    start_codons: Vec<VecDeque<u8>>,
    stop_codons: Vec<VecDeque<u8>>,
    min_len: usize,
}

impl Finder {
    /// Create a new instance of a finder for the given start and stop codons and a particular length
    pub fn new<'a>(
        start_codons: Vec<&'a [u8; 3]>,
        stop_codons: Vec<&'a [u8; 3]>,
        min_len: usize,
    ) -> Self {
        Finder {
            start_codons: start_codons
                .iter() // Convert start_ and
                .map(|x| {
                    // stop_codons from
                    x.iter() // Vec<&[u8;3]> to
                        .map(|&x| x as u8) // Vec<VecDeque<u8>>
                        .collect::<VecDeque<u8>>() // so they can be
                }) // easily compared
                .collect(), // with codon built
            stop_codons: stop_codons
                .iter() // from IntoTextIterator
                .map(|x| {
                    // object.
                    x.iter().map(|&x| x as u8).collect::<VecDeque<u8>>()
                })
                .collect(),
            min_len,
        }
    }

    /// Find all orfs in the given sequence
    pub fn find_all<C, T>(&self, seq: T) -> Matches<'_, C, T::IntoIter>
    where
        C: Borrow<u8>,
        T: IntoIterator<Item = C>,
    {
        Matches {
            finder: self,
            state: State::new(),
            seq: seq.into_iter().enumerate(),
        }
    }
}

/// An orf representation with start and end position of said orf,
/// as well as offset of the reading frame (1,2,3) and strand location
// (current: +, reverse complementary: -).
pub struct Orf {
    pub start: usize,
    pub end: usize,
    pub offset: i8,
}

/// The current algorithm state.
struct State {
    start_pos: [Option<usize>; 3],
    codon: VecDeque<u8>,
}

impl State {
    /// Create new state.
    pub fn new() -> Self {
        State {
            start_pos: [None, None, None],
            codon: VecDeque::new(),
        }
    }
}

/// Iterator over offset, start position, end position and sequence of matched orfs.
pub struct Matches<'a, C, T>
where
    C: Borrow<u8>,
    T: Iterator<Item = C>,
{
    finder: &'a Finder,
    state: State,
    seq: iter::Enumerate<T>,
}

impl<'a, C, T> Iterator for Matches<'a, C, T>
where
    C: Borrow<u8>,
    T: Iterator<Item = C>,
{
    type Item = Orf;

    fn next(&mut self) -> Option<Orf> {
        let mut result: Option<Orf> = None;
        let mut offset: usize;

        for (index, nuc) in self.seq.by_ref() {
            // update the codon
            if self.state.codon.len() >= 3 {
                self.state.codon.pop_front();
            }
            self.state.codon.push_back(*nuc.borrow());
            offset = (index + 1) % 3;

            // inside orf
            if self.state.start_pos[offset].is_some() {
                // check if leaving orf
                if self.finder.stop_codons.contains(&self.state.codon) {
                    // check if length is sufficient
                    if index + 1 - self.state.start_pos[offset].unwrap() > self.finder.min_len {
                        // build results
                        result = Some(Orf {
                            start: self.state.start_pos[offset].unwrap() - 2,
                            end: index + 1,
                            offset: offset as i8,
                        });
                    }
                    // reinitialize
                    self.state.start_pos[offset] = None;
                }
            // check if entering orf
            } else if self.finder.start_codons.contains(&self.state.codon) {
                self.state.start_pos[offset] = Some(index);
            }
            if result.is_some() {
                return result;
            }
        }
        None
    }
}

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

    #[test]
    fn test_orf() {
        let start_codons = vec![b"ATG"];
        let stop_codons = vec![b"TGA", b"TAG", b"TAA"];
        let min_len = 50;
        let finder = Finder::new(start_codons, stop_codons, min_len);

        let sequence = b"ACGGCTAGAAAAGGCTAGAAAA";

        for Orf { start, end, .. } in finder.find_all(sequence) {
            let _ = &sequence[start..end];
        }
    }
}
<commit_msg>Add tests for orf finding algorithm (#262)<commit_after>// Copyright 2014-2016 Johannes Köster, Martin Larralde.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! One-way orf finder algorithm.
//!
//! Complexity: O(n).
//!
//! # Example
//!
//! ```
//! use bio::seq_analysis::orf::{Finder, Orf};
//! let start_codons = vec!(b"ATG");
//! let stop_codons  = vec!(b"TGA", b"TAG", b"TAA");
//! let min_len = 50;
//! let finder = Finder::new(start_codons, stop_codons, min_len);
//!
//! let sequence = b"ACGGCTAGAAAAGGCTAGAAAA";
//!
//! for Orf{start, end, offset} in finder.find_all(sequence) {
//!    let orf = &sequence[start..end];
//!    //...do something with orf sequence...
//! }
//! ```
//!
//! Right now the only way to check the reverse strand for orf is to use
//! the `alphabet::dna::RevComp` struct and to check for both sequences.
//! But that's not so performance friendly, as the reverse complementation and the orf research
//! could go on at the same time.

use std::borrow::Borrow;
use std::collections::VecDeque;
use std::iter;

/// An implementation of a naive algorithm finder
pub struct Finder {
    start_codons: Vec<VecDeque<u8>>,
    stop_codons: Vec<VecDeque<u8>>,
    min_len: usize,
}

impl Finder {
    /// Create a new instance of a finder for the given start and stop codons and a particular length
    pub fn new<'a>(
        start_codons: Vec<&'a [u8; 3]>,
        stop_codons: Vec<&'a [u8; 3]>,
        min_len: usize,
    ) -> Self {
        Finder {
            start_codons: start_codons
                .iter() // Convert start_ and
                .map(|x| {
                    // stop_codons from
                    x.iter() // Vec<&[u8;3]> to
                        .map(|&x| x as u8) // Vec<VecDeque<u8>>
                        .collect::<VecDeque<u8>>() // so they can be
                }) // easily compared
                .collect(), // with codon built
            stop_codons: stop_codons
                .iter() // from IntoTextIterator
                .map(|x| {
                    // object.
                    x.iter().map(|&x| x as u8).collect::<VecDeque<u8>>()
                })
                .collect(),
            min_len,
        }
    }

    /// Find all orfs in the given sequence
    pub fn find_all<C, T>(&self, seq: T) -> Matches<'_, C, T::IntoIter>
    where
        C: Borrow<u8>,
        T: IntoIterator<Item = C>,
    {
        Matches {
            finder: self,
            state: State::new(),
            seq: seq.into_iter().enumerate(),
        }
    }
}

/// An orf representation with start and end position of said orf,
/// as well as offset of the reading frame (1,2,3) and strand location
// (current: +, reverse complementary: -).
#[derive(Debug, PartialEq)]
pub struct Orf {
    pub start: usize,
    pub end: usize,
    pub offset: i8,
}

/// The current algorithm state.
struct State {
    start_pos: [Option<usize>; 3],
    codon: VecDeque<u8>,
}

impl State {
    /// Create new state.
    pub fn new() -> Self {
        State {
            start_pos: [None, None, None],
            codon: VecDeque::new(),
        }
    }
}

/// Iterator over offset, start position, end position and sequence of matched orfs.
pub struct Matches<'a, C, T>
where
    C: Borrow<u8>,
    T: Iterator<Item = C>,
{
    finder: &'a Finder,
    state: State,
    seq: iter::Enumerate<T>,
}

impl<'a, C, T> Iterator for Matches<'a, C, T>
where
    C: Borrow<u8>,
    T: Iterator<Item = C>,
{
    type Item = Orf;

    fn next(&mut self) -> Option<Orf> {
        let mut result: Option<Orf> = None;
        let mut offset: usize;

        for (index, nuc) in self.seq.by_ref() {
            // update the codon
            if self.state.codon.len() >= 3 {
                self.state.codon.pop_front();
            }
            self.state.codon.push_back(*nuc.borrow());
            offset = (index + 1) % 3;

            // inside orf
            if self.state.start_pos[offset].is_some() {
                // check if leaving orf
                if self.finder.stop_codons.contains(&self.state.codon) {
                    // check if length is sufficient
                    if index + 1 - self.state.start_pos[offset].unwrap() > self.finder.min_len {
                        // build results
                        result = Some(Orf {
                            start: self.state.start_pos[offset].unwrap() - 2,
                            end: index + 1,
                            offset: offset as i8,
                        });
                    }
                    // reinitialize
                    self.state.start_pos[offset] = None;
                }
            // check if entering orf
            } else if self.finder.start_codons.contains(&self.state.codon) {
                self.state.start_pos[offset] = Some(index);
            }
            if result.is_some() {
                return result;
            }
        }
        None
    }
}

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

    fn basic_finder() -> Finder {
        let start_codons = vec![b"ATG"];
        let stop_codons = vec![b"TGA", b"TAG", b"TAA"];
        let min_len = 5;
        Finder::new(start_codons, stop_codons, min_len)
    }

    #[test]
    fn test_no_orf() {
        let finder = basic_finder();
        let sequence = b"ACGGCTAGAAAAGGCTAGAAAA";
        assert!(finder.find_all(sequence).collect::<Vec<Orf>>().is_empty());
    }

    #[test]
    fn test_one_orf_no_offset() {
        let finder = basic_finder();
        let sequence = b"GGGATGGGGTGAGGG";
        let expected = vec![Orf {
            start: 3,
            end: 12,
            offset: 0,
        }];
        assert_eq!(expected, finder.find_all(sequence).collect::<Vec<Orf>>());
    }

    #[test]
    fn test_one_orf_with_offset() {
        let finder = basic_finder();
        let sequence = b"AGGGATGGGGTGAGGG";
        let expected = vec![Orf {
            start: 4,
            end: 13,
            offset: 1,
        }];
        assert_eq!(expected, finder.find_all(sequence).collect::<Vec<Orf>>());
    }

    #[test]
    fn test_two_orfs_different_offsets() {
        let finder = basic_finder();
        let sequence = b"ATGGGGTGAGGGGGATGGAAAAATAAG";
        let expected = vec![
            Orf {
                start: 0,
                end: 9,
                offset: 0,
            },
            Orf {
                start: 14,
                end: 26,
                offset: 2,
            },
        ];
        assert_eq!(expected, finder.find_all(sequence).collect::<Vec<Orf>>());
    }
}
<|endoftext|>


<commit_before>//! It's a tree!

use std::ptr;

use rustwlc::handle::WlcView;

use super::container::*;

#[derive(Debug, PartialEq, Eq)]
pub struct Node {
    // We need a mut pointer so we can modify the parent
    parent: *mut Node,
    val: Container,
    children: Vec<Node>
}

impl Node {
    /// Create a new node with the existing value.
    /// For root-style constructors.
    pub fn new(val: Container) -> Node {
        Node {
            parent: ptr::null_mut(),
            val: val,
            children: Vec::new()
        }
    }

    /// Add a new child node to this node, using a value
    pub fn new_child(&mut self, val: Container) -> &mut Node {
        let self_mut = self as *mut Node;
        self.children.push(Node {
            parent: self_mut,
            val: val,
            children: Vec::new()
        });
        let last_ix = self.children.len() -1;
        &mut self.children[last_ix]
    }

    /// Whether this node has a (currently-reachable) parent
    #[allow(dead_code)]
    pub fn has_parent(&self) -> bool {
        !self.parent.is_null()
    }

    /// Gets the type of container this node holds
    pub fn get_container_type(&self) -> ContainerType {
        self.val.get_type()
    }

    /// Tries to get an ancestor of the requested type
    pub fn get_ancestor_of_type(&self, container_type: ContainerType)
                                -> Option<&Node> {
        let mut maybe_parent = self.get_parent();
        loop {
            if let Some(parent) = maybe_parent {
                if parent.get_container_type() == container_type {
                    return Some(parent);
                }
                maybe_parent = parent.get_parent();
            }
            else {
                return None;
            }
        }
    }

    /// Gets a node by handle
    pub fn find_view_by_handle(&self, view_handle: &WlcView) -> Option<&Node>{
        match self.get_val() {
            &Container::View { ref handle, .. } => {
                if view_handle == handle {
                    Some(self)
                } else {
                    None
                }
            },
            _ => {
                for child in self.get_children() {
                    if let Some(view) = child.find_view_by_handle(view_handle) {
                        return Some(view);
                    }
                }
                return None;
            }
        }
    }

    /// Gets the parent of this node (if it exists)
    pub fn get_parent(&self) -> Option<&mut Node> {
        if self.parent.is_null() {
            return None;
        }
        unsafe {
            return Some(&mut *self.parent);
        }
    }

    /// Borrow the children of this node.
    pub fn get_children(&self) -> &[Node] {
        &self.children
    }

    /// Mutably borrow the children of this mutable node
    pub fn get_children_mut(&mut self) -> &mut[Node] {
        &mut self.children
    }

    /// Remove a child at the given index
    #[allow(dead_code)]
    pub fn remove_child_at(&mut self, index: usize) -> Option<Node> {
        if index > self.children.len() - 1 {
            return None;
        }
        let mut child = self.children.remove(index);
        child.parent = ptr::null_mut();
        return Some(child);
    }

    /// Moves another node to be a sibling of this node.
    #[allow(dead_code)]
    pub fn add_sibling(&self, node: Node) -> Result<(), ()> {
        if let Some(parent) = self.get_parent() {
            node.move_to(parent);
            Ok(())
        }
        else {
            Err(())
        }
    }

    /// Whether this node is a parent of another node
    #[allow(dead_code)]
    pub fn is_parent_of(&self, other: &Node) -> bool {
        // Fun fact, other.parent == self as *const Node won't compile
        self as *const Node == other.parent
    }

    /// Remove a node from its parent.
    /// This method will mutate the parent if it exists.
    pub fn remove_from_parent(&mut self) -> Option<Node> {
        let mut result: Option<Node> = None;
        if let Some(mut parent) = self.get_parent() {
            if let Some(index) = parent.children.iter().position(|c| c == self) {
                result = Some(parent.children.remove(index));
            }
        }
        self.parent = ptr::null_mut();
        result
    }

    /// Removes a child from self
    pub fn remove_child(&mut self, other: &Node) -> Option<Node> {
        if let Some(index) = self.children.iter().position(|c| c == other) {
            let mut child = self.children.remove(index);
            child.parent = ptr::null_mut();
            Some(child)
        }
        else {
            None
        }
    }

    pub fn move_to(mut self, new_parent: &mut Node) {
        self.remove_from_parent();
        self.parent = new_parent as *mut Node;
        new_parent.children.push(self);
    }

    pub fn get_val(&self) -> &Container {
        &self.val
    }

    /// Sets the visibility of the container and its children
    pub fn set_visibility(&mut self, visibility: bool) {
        self.val.set_visibility(visibility);
        for child in self.get_children_mut() {
            child.set_visibility(visibility);
        }
    }
}

impl Drop for Node {
    fn drop(&mut self) {
        println!("Dropping a node.");
        let children: &mut Vec<Node> = &mut self.children;
        for mut child in children {
            child.parent = ptr::null_mut();
        }
    }
}

unsafe impl Sync for Node {}
unsafe impl Send for Node {}

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

    /// Nodes can have children added to them
    #[test]
    fn new_child() {
        let mut root = Node::new(Container::Root);
        root.new_child(Container::Root);
        root.new_child(Container::Root); // This is okay
        {
            let mut third_child = root.new_child(Container::Root);
            third_child.new_child(Container::Root);
            //root.new_child(Root); // Have to wait for 3rd child to drop
        }
        root.new_child(Container::Root); // Now this works
        assert_eq!(root.children.len(), 4);
    }

    #[test]
    fn has_get_parent() {
        let mut root = Node::new(Container::Root);
        assert!(!root.has_parent(), "Root has a parent");
        assert_eq!(root.get_parent(), None);

        let child = root.new_child(Container::Root);
        assert!(child.has_parent(), "Child does not have parent");
        assert!(child.get_parent().is_some(), "Child does not have parent");
        let parent = child.get_parent().expect("Asserted child has parent");
        assert_eq!(parent.get_container_type(), ContainerType::Root);
    }

    #[test]
    fn get_container_type() {
        let mut root = Node::new(Container::Root);
        assert_eq!(root.get_container_type(), ContainerType::Root);
        {
            let wksp = root.new_child(
                Container::Workspace { name: "Foo".to_string(),
                                       focused: false });
            assert_eq!(wksp.get_container_type(), ContainerType::Workspace);
        }
        {
            let container = root.new_child(Container::Container {
                layout: Layout::Horizontal, visible: false,
                floating: false, focused: false
            });
            assert_eq!(container.get_container_type(), ContainerType::Container);
        }
    }

    #[test]
    fn get_children() {
        // Create a root with 3 children. The 3rd child has 2 children.
        let mut root = Node::new(Container::Root);
        root.new_child(Container::Root);
        root.new_child(Container::Root);
        {
            let third_child = root.new_child(Container::Root);
            third_child.new_child(Container::Root);
            third_child.new_child(Container::Root);
        }
        let root_children = root.get_children();
        assert!(!root_children.is_empty(), "Root has children");
        assert_eq!(root_children.len(), 3);
        assert!(root_children.last().is_some(), "Root has final child");
        let third_child = root_children.last().expect("Asserted unwrap!");
        assert_eq!(third_child.get_children().len(), 2);
        let third_child_second_child = third_child.get_children().last()
            .expect("Asserted unwrap!");
        assert!(third_child_second_child.get_children().is_empty(),
                "Grandchild doesn't have children");
    }

    #[test]
    fn get_children_mut() {
        // Start out with one child, use get_mut_children to add grandchild.
        let mut root = Node::new(Container::Root);
        root.new_child(Container::Root);

        assert!(root.get_children().last().expect("Root has child")
                .get_children().is_empty(), "Root has no grandchildren");

        {
            let mut children = root.get_children_mut();
            assert_eq!(children.len(), 1);

            let mut child = &mut children[0];
            child.new_child(Container::Root);
        }

        assert_eq!(root.get_children().last().expect("Asserted unwrap!")
                .get_children().len(), 1);
    }

    #[test]
    fn remove_child_at() {
        let mut root = Node::new(Container::Root);
        root.new_child(Container::Root);
        root.new_child(Container::Workspace {
            name: "Foo".to_string(), focused: false
        });
        root.new_child(Container::Root);

        let worksp = root.remove_child_at(1).expect("Index should be valid");
        assert_eq!(worksp.get_container_type(), ContainerType::Workspace);
        assert_eq!(root.get_children().len(), 2)
    }
}
<commit_msg>Finished up documenting functions in node.rs<commit_after>//! It's a tree!

use std::ptr;

use rustwlc::handle::WlcView;

use super::container::*;

#[derive(Debug, PartialEq, Eq)]
pub struct Node {
    // We need a mut pointer so we can modify the parent
    parent: *mut Node,
    val: Container,
    children: Vec<Node>
}

impl Node {
    /// Create a new node with the existing value.
    /// For root-style constructors.
    pub fn new(val: Container) -> Node {
        Node {
            parent: ptr::null_mut(),
            val: val,
            children: Vec::new()
        }
    }

    /// Add a new child node to this node, using a value
    pub fn new_child(&mut self, val: Container) -> &mut Node {
        let self_mut = self as *mut Node;
        self.children.push(Node {
            parent: self_mut,
            val: val,
            children: Vec::new()
        });
        let last_ix = self.children.len() -1;
        &mut self.children[last_ix]
    }

    /// Whether this node has a (currently-reachable) parent
    #[allow(dead_code)]
    pub fn has_parent(&self) -> bool {
        !self.parent.is_null()
    }

    /// Gets the type of container this node holds
    pub fn get_container_type(&self) -> ContainerType {
        self.val.get_type()
    }

    /// Tries to get an ancestor of the requested type
    pub fn get_ancestor_of_type(&self, container_type: ContainerType)
                                -> Option<&Node> {
        let mut maybe_parent = self.get_parent();
        loop {
            if let Some(parent) = maybe_parent {
                if parent.get_container_type() == container_type {
                    return Some(parent);
                }
                maybe_parent = parent.get_parent();
            }
            else {
                return None;
            }
        }
    }

    /// Gets a node by handle
    pub fn find_view_by_handle(&self, view_handle: &WlcView) -> Option<&Node>{
        match self.get_val() {
            &Container::View { ref handle, .. } => {
                if view_handle == handle {
                    Some(self)
                } else {
                    None
                }
            },
            _ => {
                for child in self.get_children() {
                    if let Some(view) = child.find_view_by_handle(view_handle) {
                        return Some(view);
                    }
                }
                return None;
            }
        }
    }

    /// Gets the parent of this node (if it exists)
    pub fn get_parent(&self) -> Option<&mut Node> {
        if self.parent.is_null() {
            return None;
        }
        unsafe {
            return Some(&mut *self.parent);
        }
    }

    /// Borrow the children of this node.
    pub fn get_children(&self) -> &[Node] {
        &self.children
    }

    /// Mutably borrow the children of this mutable node
    pub fn get_children_mut(&mut self) -> &mut[Node] {
        &mut self.children
    }

    /// Remove a child at the given index
    #[allow(dead_code)]
    pub fn remove_child_at(&mut self, index: usize) -> Option<Node> {
        if index > self.children.len() - 1 {
            return None;
        }
        let mut child = self.children.remove(index);
        child.parent = ptr::null_mut();
        return Some(child);
    }

    /// Moves another node to be a sibling of this node.
    #[allow(dead_code)]
    pub fn add_sibling(&self, node: Node) -> Result<(), ()> {
        if let Some(parent) = self.get_parent() {
            node.move_to(parent);
            Ok(())
        }
        else {
            Err(())
        }
    }

    /// Whether this node is a parent of another node
    #[allow(dead_code)]
    pub fn is_parent_of(&self, other: &Node) -> bool {
        // Fun fact, other.parent == self as *const Node won't compile
        self as *const Node == other.parent
    }

    /// Remove a node from its parent.
    /// This method will mutate the parent if it exists.
    pub fn remove_from_parent(&mut self) -> Option<Node> {
        let mut result: Option<Node> = None;
        if let Some(mut parent) = self.get_parent() {
            if let Some(index) = parent.children.iter().position(|c| c == self) {
                result = Some(parent.children.remove(index));
            }
        }
        self.parent = ptr::null_mut();
        result
    }

    /// Removes a child from self
    pub fn remove_child(&mut self, other: &Node) -> Option<Node> {
        if let Some(index) = self.children.iter().position(|c| c == other) {
            let mut child = self.children.remove(index);
            child.parent = ptr::null_mut();
            Some(child)
        }
        else {
            None
        }
    }

    /// Removes this node from its current parent and adds it to the given node
    /// as a child
    pub fn move_to(mut self, new_parent: &mut Node) {
        self.remove_from_parent();
        self.parent = new_parent as *mut Node;
        new_parent.children.push(self);
    }

    /// Gets the container that this node has
    pub fn get_val(&self) -> &Container {
        &self.val
    }

    /// Sets the visibility of the container and its children
    pub fn set_visibility(&mut self, visibility: bool) {
        self.val.set_visibility(visibility);
        for child in self.get_children_mut() {
            child.set_visibility(visibility);
        }
    }
}

impl Drop for Node {
    fn drop(&mut self) {
        println!("Dropping a node.");
        let children: &mut Vec<Node> = &mut self.children;
        for mut child in children {
            child.parent = ptr::null_mut();
        }
    }
}

unsafe impl Sync for Node {}
unsafe impl Send for Node {}

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

    /// Nodes can have children added to them
    #[test]
    fn new_child() {
        let mut root = Node::new(Container::Root);
        root.new_child(Container::Root);
        root.new_child(Container::Root); // This is okay
        {
            let mut third_child = root.new_child(Container::Root);
            third_child.new_child(Container::Root);
            //root.new_child(Root); // Have to wait for 3rd child to drop
        }
        root.new_child(Container::Root); // Now this works
        assert_eq!(root.children.len(), 4);
    }

    #[test]
    fn has_get_parent() {
        let mut root = Node::new(Container::Root);
        assert!(!root.has_parent(), "Root has a parent");
        assert_eq!(root.get_parent(), None);

        let child = root.new_child(Container::Root);
        assert!(child.has_parent(), "Child does not have parent");
        assert!(child.get_parent().is_some(), "Child does not have parent");
        let parent = child.get_parent().expect("Asserted child has parent");
        assert_eq!(parent.get_container_type(), ContainerType::Root);
    }

    #[test]
    fn get_container_type() {
        let mut root = Node::new(Container::Root);
        assert_eq!(root.get_container_type(), ContainerType::Root);
        {
            let wksp = root.new_child(
                Container::Workspace { name: "Foo".to_string(),
                                       focused: false });
            assert_eq!(wksp.get_container_type(), ContainerType::Workspace);
        }
        {
            let container = root.new_child(Container::Container {
                layout: Layout::Horizontal, visible: false,
                floating: false, focused: false
            });
            assert_eq!(container.get_container_type(), ContainerType::Container);
        }
    }

    #[test]
    fn get_children() {
        // Create a root with 3 children. The 3rd child has 2 children.
        let mut root = Node::new(Container::Root);
        root.new_child(Container::Root);
        root.new_child(Container::Root);
        {
            let third_child = root.new_child(Container::Root);
            third_child.new_child(Container::Root);
            third_child.new_child(Container::Root);
        }
        let root_children = root.get_children();
        assert!(!root_children.is_empty(), "Root has children");
        assert_eq!(root_children.len(), 3);
        assert!(root_children.last().is_some(), "Root has final child");
        let third_child = root_children.last().expect("Asserted unwrap!");
        assert_eq!(third_child.get_children().len(), 2);
        let third_child_second_child = third_child.get_children().last()
            .expect("Asserted unwrap!");
        assert!(third_child_second_child.get_children().is_empty(),
                "Grandchild doesn't have children");
    }

    #[test]
    fn get_children_mut() {
        // Start out with one child, use get_mut_children to add grandchild.
        let mut root = Node::new(Container::Root);
        root.new_child(Container::Root);

        assert!(root.get_children().last().expect("Root has child")
                .get_children().is_empty(), "Root has no grandchildren");

        {
            let mut children = root.get_children_mut();
            assert_eq!(children.len(), 1);

            let mut child = &mut children[0];
            child.new_child(Container::Root);
        }

        assert_eq!(root.get_children().last().expect("Asserted unwrap!")
                .get_children().len(), 1);
    }

    #[test]
    fn remove_child_at() {
        let mut root = Node::new(Container::Root);
        root.new_child(Container::Root);
        root.new_child(Container::Workspace {
            name: "Foo".to_string(), focused: false
        });
        root.new_child(Container::Root);

        let worksp = root.remove_child_at(1).expect("Index should be valid");
        assert_eq!(worksp.get_container_type(), ContainerType::Workspace);
        assert_eq!(root.get_children().len(), 2)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 William (B.J.) Snow Orvis
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Lindenmayer systems are a methodology for representing various kinds of
//! iterated curves or other constructions. A given system has an alphabet of
//! symbols, an initial string, and one or more rules for transforming that
//! string into the next iteration/generation.
//!
//! The resulting string at a given iteration or generation can represent a
//! sequence of commands that some representation process, such as a turtle
//! drawing program, can then use to draw a curve/fractal/plant (which is what
//! this implementation provides).

use std::marker::PhantomData;

use geometry::Point;
use turtle::*;

/// Represents a particular Lindenmayer system. It requires an alphabet (represented as an enum),
/// an initial sequence ("string"), and one or more rules that transform the sequence with each
/// iteration/generation.
///
/// Under many circumstances, these methods will not actually use &self. However, having a &self
/// allows for more flexibility, such as creating caching objects or creating L-systems that can be
/// defined at runtime instead of at compile time.
pub trait LindenmayerSystem<Alphabet: Clone> {
    /// Should return the initial Lindenmayer system string (iteration 0).
    fn initial(&self) -> Vec<Alphabet>;

    /// Apply Lindenmayer system rules to a given character.
    ///
    /// A common implementation approach would be to use `match` with the Alphabet. For example:
    ///
    /// ```
    /// use fractal::lindenmayer::LindenmayerSystem;
    ///
    /// /// Our Alphbet
    /// #[derive(Clone)]
    /// enum SomeAlphabet { A, B, C, Foo }
    ///
    /// struct SomeLSystem;
    ///
    /// impl LindenmayerSystem<SomeAlphabet> for SomeLSystem {
    ///      fn initial(&self) -> Vec<SomeAlphabet> {
    ///          vec![SomeAlphabet::A, SomeAlphabet::B, SomeAlphabet::C]
    ///      }
    ///
    ///     fn apply_rule(&self, l: SomeAlphabet) -> Vec<SomeAlphabet> {
    ///         match l {
    ///             SomeAlphabet::A => vec![SomeAlphabet::A, SomeAlphabet::Foo, SomeAlphabet::B, SomeAlphabet::C],
    ///             SomeAlphabet::B => vec![SomeAlphabet::Foo],
    ///             SomeAlphabet::C => vec![SomeAlphabet::Foo, SomeAlphabet::B],
    ///             SomeAlphabet::Foo => vec![SomeAlphabet::Foo],
    ///         }
    ///     }
    /// }
    /// ```
    fn apply_rule(&self, curr_symbol: Alphabet) -> Vec<Alphabet>;

    /// Generates a Lindenmayer system string for `iteration`.
    ///
    /// This is done by starting with the initial sequence, and repeatedly applying the rules to
    /// the sequence `iteration` times. The result is a new vector that contains the sequence for
    /// the specified iteration.
    fn generate(&self, iteration: u64) -> Vec<Alphabet> {
        let mut lstr: Vec<Alphabet> = Self::initial();
        let mut i = 0;
        while i < iteration {
            i = i + 1;
            let mut newlstr: Vec<Alphabet> = vec![];

            for l in lstr.iter().cloned() {
                for other in Self::apply_rule(l).iter().cloned() {
                    newlstr.push(other);
                }
            }
            lstr = newlstr;
        }
        lstr
    }
}

/// In order to draw a fractal using a Lindenmayer System, we need to translate the output from the
/// L-System into turtle commands. To do this, we need to initial the turtle, and we need a way to
/// convert the L-System's symbols into actions. This trait provides the methods needed to
/// configure the LindenmayerSystemTurtleProgram, which is the glue that issues arbitrary Turtle
/// commands.
pub trait LindenmayerSystemDrawingParameters<Alphabet> {
    /// Returns the iteration that should be drawn.
    fn iteration(&self) -> u64;

    /// Specifies the turtle's initial position. Defaults to (0.0, 0.0).
    fn initial_pos(&self) -> Point {
        Point { x: 0.0, y: 0.0 }
    }

    /// Specifies the turtle's initial direction. Defaults to 0.0.
    fn initial_rad(&self) -> f64 {
        0.0
    }

    /// Convert symbol into a turtle command.
    ///
    /// Usually, when moving the turtle forwards, there is some formula that will ensure that the
    /// turtle always ends at a given point, such as at (1.0, 0.0).
    fn interpret_symbol(&self, symbol: Alphabet) -> TurtleStep;
}

pub struct LindenmayerSystemTurtleProgram<L, A>
    where L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A>,
          A: Clone + 'static
{
    alphabet: PhantomData<A>,
    system: L,
}

impl<'a, L, A> LindenmayerSystemTurtleProgram<L, A>
    where L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A>,
          A: Clone
{
    pub fn new(system: L) -> LindenmayerSystemTurtleProgram<L, A> {
        LindenmayerSystemTurtleProgram {
            system: system,
            alphabet: PhantomData,
        }
    }
}

impl<L, A> TurtleProgram for LindenmayerSystemTurtleProgram<L, A>
    where L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
          A: Clone + 'static
{
    fn init_turtle(&self) -> Vec<TurtleStep> {
        vec![
            TurtleStep::SetPos(self.system.initial_pos()),
            TurtleStep::SetRad(self.system.initial_rad()),
            TurtleStep::Down,
        ]
    }

    fn turtle_program_iter<'a>(&'a self) -> TurtleProgramIterator<'a> {
        println!("Generating L-System sequence...");
        let sequence = self.system.generate(self.system.iteration());
        println!("Done");

        TurtleProgramIterator::new(Box::new(LindenmayerSystemTurtleProgramIterator {
            alphabet: PhantomData,
            program: self,
            sequence: sequence,
            curr_step: 0,
        }))
    }
}

pub struct LindenmayerSystemTurtleProgramIterator<'a, L, A>
    where L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
          A: Clone + 'static
{
    alphabet: PhantomData<A>,
    program: &'a LindenmayerSystemTurtleProgram<L, A>,
    sequence: Vec<A>,
    curr_step: usize,
}

impl<'a, L, A> Iterator for LindenmayerSystemTurtleProgramIterator<'a, L, A>
    where L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
          A: Clone + 'static
{
    type Item = TurtleStep;

    fn next(&mut self) -> Option<TurtleStep> {
        if self.curr_step >= self.sequence.len() {
            return None;
        }

        let symbol = self.sequence[self.curr_step].clone();
        self.curr_step += 1;

        Some(self.program.system.interpret_symbol(symbol))
    }
}

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

    #[derive(Clone, PartialEq, Eq, Debug)]
    enum TestABC {
        A,
        B,
        C,
        Foo,
    }

    struct TestLS;

    impl LindenmayerSystem<TestABC> for TestLS {
        fn initial(&self) -> Vec<TestABC> {
            vec![TestABC::A, TestABC::B, TestABC::C]
        }

        fn apply_rule(&self, l: TestABC) -> Vec<TestABC> {
            match l {
                TestABC::A => vec![TestABC::A, TestABC::Foo, TestABC::B, TestABC::C],
                TestABC::B => vec![TestABC::Foo],
                TestABC::C => vec![TestABC::Foo, TestABC::B],
                TestABC::Foo => vec![TestABC::Foo],
            }
        }
    }

    /// Test a sample TestLS system
    #[test]
    fn test_lsystem() {
        assert_eq!(TestLS.generate(0), [TestABC::A, TestABC::B, TestABC::C]);
        assert_eq!(TestLS.generate(1),
                   [TestABC::A,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::C,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::B]);
        assert_eq!(TestLS.generate(2),
                   [TestABC::A,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::C,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo]);
        assert_eq!(TestLS.generate(3),
                   [TestABC::A,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::C,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo]);
    }
}
<commit_msg>Adding support to cache L-system strings.<commit_after>// Copyright (c) 2015-2016 William (B.J.) Snow Orvis
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Lindenmayer systems are a methodology for representing various kinds of
//! iterated curves or other constructions. A given system has an alphabet of
//! symbols, an initial string, and one or more rules for transforming that
//! string into the next iteration/generation.
//!
//! The resulting string at a given iteration or generation can represent a
//! sequence of commands that some representation process, such as a turtle
//! drawing program, can then use to draw a curve/fractal/plant (which is what
//! this implementation provides).

use std::cell::RefCell;
use std::marker::PhantomData;

use geometry::Point;
use turtle::*;

/// Represents a particular Lindenmayer system. It requires an alphabet (represented as an enum),
/// an initial sequence ("string"), and one or more rules that transform the sequence with each
/// iteration/generation.
///
/// Under many circumstances, these methods will not actually use &self. However, having a &self
/// allows for more flexibility, such as creating caching objects or creating L-systems that can be
/// defined at runtime instead of at compile time.
pub trait LindenmayerSystem<Alphabet: Clone> {
    /// Should return the initial Lindenmayer system string (iteration 0).
    fn initial(&self) -> Vec<Alphabet>;

    /// Apply Lindenmayer system rules to a given character.
    ///
    /// A common implementation approach would be to use `match` with the Alphabet. For example:
    ///
    /// ```
    /// use fractal::lindenmayer::LindenmayerSystem;
    ///
    /// /// Our Alphbet
    /// #[derive(Clone)]
    /// enum SomeAlphabet { A, B, C, Foo }
    ///
    /// struct SomeLSystem;
    ///
    /// impl LindenmayerSystem<SomeAlphabet> for SomeLSystem {
    ///      fn initial(&self) -> Vec<SomeAlphabet> {
    ///          vec![SomeAlphabet::A, SomeAlphabet::B, SomeAlphabet::C]
    ///      }
    ///
    ///     fn apply_rule(&self, l: SomeAlphabet) -> Vec<SomeAlphabet> {
    ///         match l {
    ///             SomeAlphabet::A => vec![SomeAlphabet::A, SomeAlphabet::Foo, SomeAlphabet::B, SomeAlphabet::C],
    ///             SomeAlphabet::B => vec![SomeAlphabet::Foo],
    ///             SomeAlphabet::C => vec![SomeAlphabet::Foo, SomeAlphabet::B],
    ///             SomeAlphabet::Foo => vec![SomeAlphabet::Foo],
    ///         }
    ///     }
    /// }
    /// ```
    fn apply_rule(&self, curr_symbol: Alphabet) -> Vec<Alphabet>;

    fn generate_next_iteration(&self, last_iteration: &Vec<Alphabet>) -> Vec<Alphabet> {
        let mut newlstr: Vec<Alphabet> = vec![];

        for l in last_iteration.iter().cloned() {
            for other in self.apply_rule(l).iter().cloned() {
                newlstr.push(other);
            }
        }
        newlstr
    }

    /// Generates a Lindenmayer system string for `iteration`.
    ///
    /// This is done by starting with the initial sequence, and repeatedly applying the rules to
    /// the sequence `iteration` times. The result is a new vector that contains the sequence for
    /// the specified iteration.
    fn generate(&self, iteration: u64) -> Vec<Alphabet> {
        let mut last: Vec<Alphabet> = self.initial();
        let mut i = 0;
        while i < iteration {
            i = i + 1;
            last = self.generate_next_iteration(&last);
        }
        last
    }
}

/// In order to draw a fractal using a Lindenmayer System, we need to translate the output from the
/// L-System into turtle commands. To do this, we need to initial the turtle, and we need a way to
/// convert the L-System's symbols into actions. This trait provides the methods needed to
/// configure the LindenmayerSystemTurtleProgram, which is the glue that issues arbitrary Turtle
/// commands.
pub trait LindenmayerSystemDrawingParameters<Alphabet> {
    /// Returns the iteration that should be drawn.
    fn iteration(&self) -> u64;

    /// Specifies the turtle's initial position. Defaults to (0.0, 0.0).
    fn initial_pos(&self) -> Point {
        Point { x: 0.0, y: 0.0 }
    }

    /// Specifies the turtle's initial direction. Defaults to 0.0.
    fn initial_rad(&self) -> f64 {
        0.0
    }

    /// Convert symbol into a turtle command.
    ///
    /// Usually, when moving the turtle forwards, there is some formula that will ensure that the
    /// turtle always ends at a given point, such as at (1.0, 0.0).
    fn interpret_symbol(&self, symbol: Alphabet) -> TurtleStep;
}

/// In order to improve the performance of using a Lindenmayer System under some circumstances, it
/// is beneficial to cache each iteration. This allows O(1) lookups for every iteration less than
/// or equal to the largest iteration already looked up at the cost of storing every iteration
/// below the largest iteration computed (the amount of memory used changes depending on
/// characteristics of the L-System, such as how rapidly the strings grow between each iteration).
pub struct LindenmayerSystemCachingDecorator<L, A>
    where L: LindenmayerSystem<A>,
          A: Clone + 'static
{
    alphabet: PhantomData<A>,
    pub system: L,
    iteration_cache: RefCell<Vec<Vec<A>>>,
}

impl<'a, L, A> LindenmayerSystemCachingDecorator<L, A>
    where L: LindenmayerSystem<A>,
          A: Clone + 'static
{
    /// Return a new LindenmayerSystemCachingDecorator that wraps the input `system` and caches its
    /// iterations.
    pub fn new(system: L) -> LindenmayerSystemCachingDecorator<L, A> {
        LindenmayerSystemCachingDecorator {
            alphabet: PhantomData,
            system: system,
            iteration_cache: RefCell::new(vec![]),
        }
    }
}

impl<L, A> LindenmayerSystem<A> for LindenmayerSystemCachingDecorator<L, A>
    where L: LindenmayerSystem<A>,
          A: Clone + 'static
{
    /// Delegate to system
    fn initial(&self) -> Vec<A> {
        self.system.initial()
    }

    /// Delegate to system
    fn apply_rule(&self, curr_symbol: A) -> Vec<A> {
        self.system.apply_rule(curr_symbol)
    }

    /// Reimplement to to use caching. Currently using recursion.
    fn generate(&self, iteration: u64) -> Vec<A> {
        {
            let cache = self.iteration_cache.borrow_mut();
            let val = cache.get(iteration as usize);
            if val.is_some() {
                println!("found {}", iteration);
                return val.unwrap().clone();
            }
        } // end borrow of the cache
        {
            println!("generating {}", iteration);
            let curr = match iteration {
                0 => self.system.initial(), // terminating case
                _ => {
                    let last = self.generate(iteration - 1);
                    self.system.generate_next_iteration(&last)
                }
            };
            let mut cache = self.iteration_cache.borrow_mut();
            cache.push(curr);
        } // end borrow of the cache
        // Now that we have cached, try again (which should use the cache)
        self.generate(iteration)
    }
}

pub struct LindenmayerSystemTurtleProgram<L, A>
    where L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A>,
          A: Clone + 'static
{
    alphabet: PhantomData<A>,
    cacheable_system: LindenmayerSystemCachingDecorator<L, A>, // system: L,
}

impl<L, A> LindenmayerSystemTurtleProgram<L, A>
    where L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A>,
          A: Clone
{
    pub fn new(system: L) -> LindenmayerSystemTurtleProgram<L, A> {
        LindenmayerSystemTurtleProgram {
            alphabet: PhantomData,
            cacheable_system: LindenmayerSystemCachingDecorator::new(system), // system: system,
        }
    }
}

impl<L, A> TurtleProgram for LindenmayerSystemTurtleProgram<L, A>
    where L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
          A: Clone + 'static
{
    fn init_turtle(&self) -> Vec<TurtleStep> {
        vec![
            TurtleStep::SetPos(self.cacheable_system.system.initial_pos()),
            TurtleStep::SetRad(self.cacheable_system.system.initial_rad()),
            TurtleStep::Down,
        ]
    }

    fn turtle_program_iter<'a>(&'a self) -> TurtleProgramIterator<'a> {
        let sequence = self.cacheable_system.generate(self.cacheable_system.system.iteration());
        println!("Done");

        TurtleProgramIterator::new(Box::new(LindenmayerSystemTurtleProgramIterator {
            alphabet: PhantomData,
            program: self,
            sequence: sequence,
            curr_step: 0,
        }))
    }
}

pub struct LindenmayerSystemTurtleProgramIterator<'a, L, A>
    where L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
          A: Clone + 'static
{
    alphabet: PhantomData<A>,
    program: &'a LindenmayerSystemTurtleProgram<L, A>,
    sequence: Vec<A>,
    curr_step: usize,
}

impl<'a, L, A> Iterator for LindenmayerSystemTurtleProgramIterator<'a, L, A>
    where L: LindenmayerSystem<A> + LindenmayerSystemDrawingParameters<A> + 'static,
          A: Clone + 'static
{
    type Item = TurtleStep;

    fn next(&mut self) -> Option<TurtleStep> {
        if self.curr_step >= self.sequence.len() {
            return None;
        }

        let symbol = self.sequence[self.curr_step].clone();
        self.curr_step += 1;

        Some(self.program.cacheable_system.system.interpret_symbol(symbol))
    }
}

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

    #[derive(Clone, PartialEq, Eq, Debug)]
    enum TestABC {
        A,
        B,
        C,
        Foo,
    }

    struct TestLS;

    impl LindenmayerSystem<TestABC> for TestLS {
        fn initial(&self) -> Vec<TestABC> {
            vec![TestABC::A, TestABC::B, TestABC::C]
        }

        fn apply_rule(&self, l: TestABC) -> Vec<TestABC> {
            match l {
                TestABC::A => vec![TestABC::A, TestABC::Foo, TestABC::B, TestABC::C],
                TestABC::B => vec![TestABC::Foo],
                TestABC::C => vec![TestABC::Foo, TestABC::B],
                TestABC::Foo => vec![TestABC::Foo],
            }
        }
    }

    /// Test a sample TestLS system
    #[test]
    fn test_lsystem() {
        assert_eq!(TestLS.generate(0), [TestABC::A, TestABC::B, TestABC::C]);
        assert_eq!(TestLS.generate(1),
                   [TestABC::A,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::C,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::B]);
        assert_eq!(TestLS.generate(2),
                   [TestABC::A,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::C,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo]);
        assert_eq!(TestLS.generate(3),
                   [TestABC::A,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::C,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo]);
    }

    /// Test the caching decorator
    #[test]
    fn test_caching() {
        // All this can really test is verify that multiple calls for the same
        // generation come out the same.
        let orig_system = TestLS;
        let system = LindenmayerSystemCachingDecorator::new(orig_system);
        // baseline
        assert_eq!(system.generate(0), [TestABC::A, TestABC::B, TestABC::C]);
        // again
        assert_eq!(system.generate(0), [TestABC::A, TestABC::B, TestABC::C]);
        // something that will require caching 1 and 2 and use 0's cache
        assert_eq!(system.generate(3),
                   [TestABC::A,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::C,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo]);
        // use cache
        assert_eq!(system.generate(3),
                   [TestABC::A,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::C,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::Foo]);
        // use cache
        assert_eq!(system.generate(1),
                   [TestABC::A,
                    TestABC::Foo,
                    TestABC::B,
                    TestABC::C,
                    TestABC::Foo,
                    TestABC::Foo,
                    TestABC::B]);
    }
}
<|endoftext|>