///|
/// Which reference-strand orientation recognized the motif.
pub(all) enum Orientation {
Forward
Reverse
} derive(Eq, Debug, ToJson, @json.FromJson)
///|
/// Certain means every possible input base satisfies the motif.
pub(all) enum Certainty {
Certain
Possible
} derive(Eq, Debug, ToJson, @json.FromJson)
///|
/// A recognition event can exist even when cleavage falls outside linear DNA.
pub(all) struct Site {
enzyme : String
start : Int
orientation : Orientation
top : Int
bottom : Int
stagger : Int
certainty : Certainty
cuttable : Bool
} derive(Eq, Debug, ToJson, @json.FromJson)
///|
fn base_mask(c : Char) -> Int {
let mut result = 0
for n in @base.IupacBase::from_char(c).expand() {
let bit = match n.to_char() {
'A' => 1
'C' => 2
'G' => 4
_ => 8
}
result = result | bit
}
result
}
///|
fn match_window(
input : Array[Int],
motif : Array[Int],
start : Int,
) -> Certainty? {
let mut certain = true
for j in 0.. Array[Site] raise RestrictError {
let n = dna.length()
let m = enzyme.motif.length()
if n * m > 10000000 {
raise LimitExceeded("SCAN_WORK")
}
let result : Array[Site] = []
if m > n {
return result
}
let input = dna.bases.to_array().map(base_mask)
let forward = enzyme.motif.to_array().map(base_mask)
let reverse = reverse_complement(Dna::new(enzyme.motif)).bases
.to_array()
.map(base_mask)
let starts = if dna.topology == Circular { n } else { n - m + 1 }
for start in 0.. ()
Some(certainty) => {
if result.length() >= 10000 {
raise LimitExceeded("SITE_MAX_10000")
}
result.push({
enzyme: enzyme.name,
start,
orientation,
top: if dna.topology == Circular {
wrap(top, n)
} else {
top
},
bottom: if dna.topology == Circular {
wrap(bottom, n)
} else {
bottom
},
stagger: bottom - top,
certainty,
cuttable: if dna.topology == Circular {
(bottom - top).abs() < n
} else {
top >= 0 && top <= n && bottom >= 0 && bottom <= n
},
})
}
}
}
}
result
}
///|
fn wrap(position : Int, length : Int) -> Int {
(position % length + length) % length
}