1 module bio.std.hts.bam.md.operation; 2 3 import bio.core.base; 4 import bio.core.sequence; 5 6 import std.conv; 7 import std.traits; 8 import std.bitmanip; 9 import std.algorithm; 10 11 /// MD tag operation types 12 enum MdOperationType : ubyte { 13 Match, 14 Mismatch, 15 Deletion 16 } 17 18 /// Single MD operation. 19 struct MdOperation { 20 21 private { 22 MdOperationType _type; 23 union { 24 uint _match; 25 NucleotideSequence _deletion; 26 Base16 _mismatch; 27 } 28 } 29 30 /// Operation type 31 MdOperationType type() @property const { 32 return _type; 33 } 34 35 /// ditto 36 void type(MdOperationType t) @property { 37 _type = t; 38 } 39 40 /// Convenience methods 41 bool is_deletion() @property const { 42 return _type == MdOperationType.Deletion; 43 } 44 45 /// ditto 46 bool is_match() @property const { 47 return _type == MdOperationType.Match; 48 } 49 50 /// ditto 51 bool is_mismatch() @property const { 52 return _type == MdOperationType.Mismatch; 53 } 54 55 /// The number of matched bases 56 ref uint match() @property { 57 return _match; 58 } 59 60 /// Mismatched reference base 61 Base16 mismatch() @property const { 62 return _mismatch; 63 } 64 65 /// ditto 66 void mismatch(Base16 base) @property { 67 _mismatch = base; 68 } 69 70 /// Deleted sequence 71 ref NucleotideSequence deletion() @property { 72 return _deletion; 73 } 74 75 static MdOperation createMatch(uint match) { 76 MdOperation m = void; 77 m._type = MdOperationType.Match; 78 m._match = match; 79 return m; 80 } 81 82 static MdOperation createDeletion(string deletion) { 83 MdOperation m = void; 84 m._type = MdOperationType.Deletion; 85 m._deletion = nucleotideSequence(sliceableString(deletion)); 86 return m; 87 } 88 89 static MdOperation createMismatch(char mismatch) { 90 MdOperation m = void; 91 m._type = MdOperationType.Mismatch; 92 m._mismatch = Base16(mismatch); 93 return m; 94 } 95 96 static MdOperation createDeletion(NucleotideSequence seq) { 97 MdOperation m = void; 98 m._type = MdOperationType.Deletion; 99 m._deletion = seq; 100 return m; 101 } 102 103 static MdOperation createMismatch(Base16 base) { 104 MdOperation m = void; 105 m._type = MdOperationType.Mismatch; 106 m._mismatch = base; 107 return m; 108 } 109 110 bool opEquals(ref const(MdOperation) other) const { 111 112 if (type != other.type) { 113 return false; 114 } 115 116 final switch (type) { 117 case MdOperationType.Match: 118 return _match == other._match; 119 case MdOperationType.Mismatch: 120 return mismatch == other.mismatch; 121 case MdOperationType.Deletion: 122 return equal(cast()_deletion, cast()other._deletion); 123 } 124 } 125 126 string toString() const { 127 final switch (type) { 128 case MdOperationType.Match: 129 return "Match(" ~ to!string(_match) ~ ")"; 130 case MdOperationType.Mismatch: 131 return "Mismatch(" ~ to!string(_mismatch) ~ ")"; 132 case MdOperationType.Deletion: 133 return "Deletion(" ~ to!string(_deletion) ~ ")"; 134 } 135 } 136 } 137 138 /// Returns MD operation with reverse-complemented data 139 MdOperation reverseMdOp(MdOperation op) { 140 if (op.is_deletion) 141 return MdOperation.createDeletion(op.deletion.reverse); 142 143 if (op.is_mismatch) 144 return MdOperation.createMismatch(op.mismatch.complement); 145 146 return op; 147 }