///|
/// SeqFeature Advanced Demo
/// Demonstrates Bio.SeqFeatureAdvanced functionality:
/// - CompoundLocation with join and order operators
/// - GenBank-format string generation
/// - LocationParser for various location string formats
/// - SeqFeatureExtended with qualifiers
/// - Location utilities (complement, shift, merge)
///
/// Run: moon run examples/seqfeature_advanced_demo/
fn main {
println("=== SeqFeature Advanced Demo ===")
// =========================================================================
// 1. CompoundLocation with join and order operators
// =========================================================================
println("")
println("--- 1. CompoundLocation Constructors ---")
let loc1 = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(1),
@bio.Position::new_exact(100),
)
let loc2 = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(200),
@bio.Position::new_exact(300),
)
let loc3 = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(400),
@bio.Position::new_exact(500),
)
println("Created three FeatureLocations:")
println(" loc1: \{@bio.location_to_string(loc1)}")
println(" loc2: \{@bio.location_to_string(loc2)}")
println(" loc3: \{@bio.location_to_string(loc3)}")
let join_loc = @bio.CompoundLocation::join([loc1, loc2, loc3])
println("")
println("Join compound location:")
println(" operator: \{join_loc.operator()}")
println(" parts count: \{join_loc.parts().length()}")
println(" GenBank string: \{join_loc.compound_to_string()}")
println(" start: \{join_loc.compound_start().repr()}")
println(" end: \{join_loc.compound_end().repr()}")
let order_loc = @bio.CompoundLocation::order([loc1, loc2])
println("")
println("Order compound location:")
println(" operator: \{order_loc.operator()}")
println(" GenBank string: \{order_loc.compound_to_string()}")
// =========================================================================
// 2. Compound locations with strand
// =========================================================================
println("")
println("--- 2. CompoundLocation with Strand ---")
let fwd1 = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(1),
@bio.Position::new_exact(100),
strand=Some(1),
)
let fwd2 = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(200),
@bio.Position::new_exact(300),
strand=Some(1),
)
let join_fwd = @bio.CompoundLocation::join([fwd1, fwd2])
println("Forward strand join: \{join_fwd.compound_to_string()}")
let rev1 = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(1),
@bio.Position::new_exact(100),
strand=Some(-1),
)
let rev2 = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(200),
@bio.Position::new_exact(300),
strand=Some(-1),
)
let join_rev = @bio.CompoundLocation::join([rev1, rev2])
println("Reverse strand join: \{join_rev.compound_to_string()}")
// =========================================================================
// 3. LocationParser - parsing location strings
// =========================================================================
println("")
println("--- 3. LocationParser ---")
try {
let parsed1 = @bio.parse_location_string("1..100")
println("")
println("Parsed: \"1..100\"")
println(" is_feature_location: \{parsed1.is_feature_location()}")
match parsed1.to_feature_location() {
Some(loc) => {
println(" start: \{loc.start().repr()}")
println(" end: \{loc.end().repr()}")
println(" strand: \{Repr(loc.strand())}")
}
None => println(" (unexpected compound location)")
}
} catch {
_ => println(" Failed to parse '1..100'")
}
try {
let parsed2 = @bio.parse_location_string("<1..100")
println("")
println("Parsed: \"<1..100\"")
println(" is_feature_location: \{parsed2.is_feature_location()}")
match parsed2.to_feature_location() {
Some(loc) => {
println(" start: \{loc.start().repr()}")
println(" end: \{loc.end().repr()}")
}
None => println(" (unexpected compound location)")
}
} catch {
_ => println(" Failed to parse '<1..100'")
}
try {
let parsed3 = @bio.parse_location_string("complement(1..100)")
println("")
println("Parsed: \"complement(1..100)\"")
println(" is_feature_location: \{parsed3.is_feature_location()}")
match parsed3.to_feature_location() {
Some(loc) => {
println(" start: \{loc.start().repr()}")
println(" end: \{loc.end().repr()}")
println(" strand: \{Repr(loc.strand())}")
}
None => println(" (unexpected compound location)")
}
} catch {
_ => println(" Failed to parse 'complement(1..100)'")
}
try {
let parsed4 = @bio.parse_location_string("join(1..100,200..300)")
println("")
println("Parsed: \"join(1..100,200..300)\"")
println(" is_compound_location: \{parsed4.is_compound_location()}")
match parsed4.to_compound_location() {
Some(comp) => {
println(" operator: \{comp.operator()}")
println(" parts count: \{comp.parts().length()}")
println(" GenBank: \{comp.compound_to_string()}")
}
None => println(" (unexpected feature location)")
}
} catch {
_ => println(" Failed to parse 'join(1..100,200..300)'")
}
try {
let parsed5 = @bio.parse_location_string(
"complement(join(1..100,200..300))",
)
println("")
println("Parsed: \"complement(join(1..100,200..300))\"")
println(" is_compound_location: \{parsed5.is_compound_location()}")
match parsed5.to_compound_location() {
Some(comp) => {
println(" operator: \{comp.operator()}")
println(" parts count: \{comp.parts().length()}")
println(" GenBank: \{comp.compound_to_string()}")
}
None => println(" (unexpected feature location)")
}
} catch {
_ => println(" Failed to parse 'complement(join(1..100,200..300))'")
}
// =========================================================================
// 4. SeqFeatureExtended with qualifiers
// =========================================================================
println("")
println("--- 4. SeqFeatureExtended ---")
let gene_loc = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(100),
@bio.Position::new_exact(500),
strand=Some(1),
)
let gene_feature = @bio.SeqFeatureExtended::new(
gene_loc,
"gene",
id="gene_001",
description="BRCA1 gene",
)
println("Created gene feature:")
println(" type: \{gene_feature.type_()}")
println(" id: \{gene_feature.id()}")
println(" description: \{gene_feature.description()}")
println(" location: \{@bio.location_to_string(gene_feature.location())}")
let with_qualifiers = gene_feature
.add_qualifier("gene", "BRCA1")
.add_qualifier("product", "BRCA1 protein")
.add_qualifier("note", "Breast cancer susceptibility")
.add_qualifier("note", "DNA repair gene")
println("")
println("After adding qualifiers:")
println(" qualifiers count: \{with_qualifiers.qualifiers().length()}")
let notes = with_qualifiers.get_qualifier("note")
println(" 'note' values (\{notes.length()}):")
for note in notes {
println(" - \{note}")
}
println("")
println("GenBank format:")
println(with_qualifiers.seq_feature_to_string())
// =========================================================================
// 5. Location utilities
// =========================================================================
println("")
println("--- 5. Location Utilities ---")
let test_loc = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(1),
@bio.Position::new_exact(100),
)
println("location_to_string(test_loc): \{@bio.location_to_string(test_loc)}")
let fuzzy_loc = @bio.FeatureLocation::new_safe(
@bio.Position::new_before(1),
@bio.Position::new_exact(100),
)
println("location_to_string(fuzzy): \{@bio.location_to_string(fuzzy_loc)}")
let comp_loc = @bio.feature_location_complement(test_loc)
println("")
println("Complement of test_loc:")
println(" original strand: \{Repr(test_loc.strand())}")
println(" complement strand: \{Repr(comp_loc.strand())}")
println(" complement string: \{@bio.location_to_string(comp_loc)}")
let shifted = @bio.feature_location_shift(test_loc, 50)
println("")
println("Shift test_loc by +50:")
println(" original: \{@bio.location_to_string(test_loc)}")
println(" shifted: \{@bio.location_to_string(shifted)}")
let shifted_back = @bio.feature_location_shift(test_loc, -10)
println("Shift test_loc by -10:")
println(" shifted: \{@bio.location_to_string(shifted_back)}")
// Merge
println("")
println("Merge overlapping locations:")
let merge_a = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(1),
@bio.Position::new_exact(200),
strand=Some(1),
)
let merge_b = @bio.FeatureLocation::new_safe(
@bio.Position::new_exact(150),
@bio.Position::new_exact(300),
strand=Some(1),
)
println(" loc_a: \{@bio.location_to_string(merge_a)}")
println(" loc_b: \{@bio.location_to_string(merge_b)}")
try {
let merged = @bio.merge_locations(merge_a, merge_b)
println(" merged: \{@bio.location_to_string(merged)}")
} catch {
_ => println(" Failed to merge locations")
}
println("")
println("=== Demo complete ===")
}