pub fn parse_feature_row(name: &str) -> Option<FeatureRow<'_>>Expand description
Split a feature row into its fields. The channel is the innermost (last)
field, so a 3-field row is gene-level ({gene}/{modality}/{channel}) and a
4-field row carries a subunit before the channel
({gene}/{modality}/{subunit}/{channel}).
§A unit may contain /
Counting fields alone is not enough, because real gene symbols contain
slashes — standard human references ship at least one. Such a gene’s count
row has four fields and used to parse as gene = {id}_GENE1,
modality = GENE1B, subunit = count: not an error, just a different gene,
so the two channel rows of that gene stopped pairing and nothing said so.
So the modality is located by NAME, scanned from the right against
[MODALITIES], and whatever precedes it is the unit however many slashes it
contains. The subunit and channel still may not contain / — they are a
chr:pos, a component index, and a fixed token.
The two candidate positions are tried nearest-first, so a row whose unit ENDS
in a modality token reads as the gene-level form: A/count/count/spliced is
the gene A/count, not the gene A with a subunit called count. That
ambiguity is unreachable in practice — a subunit is a chr:pos or a component
index, never a modality name.
When NEITHER candidate position holds a known modality the old positional rule applies unchanged, so the producers that still emit their rows inline with a modality token outside the constant list (see the module docs) keep parsing exactly as they did. The vocabulary can only make a row parse BETTER, never make a row that parsed stop parsing.
Returns None for anything with fewer than three fields, or more than four
when no known modality locates the split.