Skip to main content

music21_rs/
variant.rs

1//! Other readings of a passage, kept beside it: music21's `variant` module.
2//!
3//! A [`Variant`] stands in a stream at the offset of the passage it is
4//! another reading of, holding that reading as a stream of its own. It
5//! takes no time in the stream holding it. Its replacement length says how
6//! much of the stream it stands in for, which may be more than it holds (a
7//! deletion), less (an elongation) or the same (a replacement).
8//!
9//! The functions here merge another version of a stream into it as
10//! variants ([`merge_variants`] and those it chooses between), add one
11//! ([`add_variant`]), find what one stands in for ([`replaced_elements`]),
12//! and make the variants of a group the stream's reading
13//! ([`Stream::activate_variants`]). They do as music21's do, the slips
14//! included: measures are found by their numbers where music21 finds them
15//! by number, and a function music21 fails in fails here too, as each one's
16//! documentation says.
17
18use std::collections::{HashMap, VecDeque};
19
20use crate::braille::equality::equal;
21use crate::defaults::{FloatType, IntegerType};
22use crate::duration::Duration;
23use crate::error::{Error, Result};
24use crate::interval::Interval;
25use crate::makenotation::op_frac;
26use crate::rest::Rest;
27use crate::search::{difflib, iterated, translate_stream_to_string};
28use crate::stream::exact::{Exact, at_offset};
29use crate::stream::{Stream, StreamElement, StreamEvent, StreamKind};
30
31/// How a [`Variant`]'s reading compares in length with the passage it
32/// stands in for: music21's `lengthType`.
33#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35pub enum LengthType {
36    /// As long as the passage.
37    Replacement,
38    /// Longer than it.
39    Elongation,
40    /// Shorter than it.
41    Deletion,
42}
43
44impl LengthType {
45    /// music21's name for the length type.
46    pub fn as_str(self) -> &'static str {
47        match self {
48            Self::Replacement => "replacement",
49            Self::Elongation => "elongation",
50            Self::Deletion => "deletion",
51        }
52    }
53}
54
55/// Another reading of a passage: music21's `Variant`.
56///
57/// ```
58/// use music21_rs::variant::{LengthType, Variant};
59/// use music21_rs::{Duration, Note};
60///
61/// let mut variant = Variant::named("ossia");
62/// variant.contents_mut().push(Note::from_name("D4")?.with_duration(Duration::half()));
63/// assert_eq!(variant.groups(), ["ossia"]);
64/// assert_eq!(variant.replacement_quarter_length(), 2.0);
65///
66/// variant.set_replacement_quarter_length(Some(4.0));
67/// assert_eq!(variant.length_type(), LengthType::Deletion);
68/// # Ok::<(), music21_rs::Error>(())
69/// ```
70#[derive(Clone, Debug, Default)]
71#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
72pub struct Variant {
73    contents: Stream,
74    groups: Vec<String>,
75    replacement_quarter_length: Option<FloatType>,
76}
77
78impl Variant {
79    /// A variant holding nothing, in no group.
80    pub fn new() -> Self {
81        Self::default()
82    }
83
84    /// A variant holding nothing, in the one group `name`: music21's
85    /// `Variant(name=...)`.
86    pub fn named(name: impl Into<String>) -> Self {
87        Self {
88            groups: vec![name.into()],
89            ..Self::default()
90        }
91    }
92
93    /// A variant holding a stream's elements where they stand in it.
94    pub fn from_stream(contents: Stream) -> Self {
95        Self {
96            contents,
97            ..Self::default()
98        }
99    }
100
101    /// The reading the variant holds: music21's `containedSite`.
102    pub fn contents(&self) -> &Stream {
103        &self.contents
104    }
105
106    /// The same, to change.
107    pub fn contents_mut(&mut self) -> &mut Stream {
108        &mut self.contents
109    }
110
111    /// The names of the readings the variant belongs to: music21's
112    /// `groups`.
113    pub fn groups(&self) -> &[String] {
114        &self.groups
115    }
116
117    /// The same, to change.
118    pub fn groups_mut(&mut self) -> &mut Vec<String> {
119        &mut self.groups
120    }
121
122    /// How much of the stream holding it the variant stands in for: the
123    /// length set, or what the reading lasts: music21's
124    /// `replacementQuarterLength`.
125    pub fn replacement_quarter_length(&self) -> FloatType {
126        self.replacement_quarter_length
127            .unwrap_or_else(|| self.contained_highest_time())
128    }
129
130    /// Sets how much of the stream the variant stands in for, or with
131    /// `None` makes it what the reading lasts.
132    pub fn set_replacement_quarter_length(&mut self, length: Option<FloatType>) {
133        self.replacement_quarter_length = length;
134    }
135
136    /// When the last thing the reading holds ends: music21's
137    /// `containedHighestTime`.
138    pub fn contained_highest_time(&self) -> FloatType {
139        highest_time(&self.contents)
140    }
141
142    /// Where the last thing the reading holds starts: music21's
143    /// `containedHighestOffset`.
144    pub fn contained_highest_offset(&self) -> FloatType {
145        self.contents
146            .events()
147            .iter()
148            .map(|event| event.offset())
149            .fold(0.0, FloatType::max)
150    }
151
152    /// Whether the reading is as long as what it stands in for, longer or
153    /// shorter: music21's `lengthType`.
154    pub fn length_type(&self) -> LengthType {
155        let difference = self.replacement_quarter_length() - self.contained_highest_time();
156        if difference > 0.0 {
157            LengthType::Deletion
158        } else if difference < 0.0 {
159            LengthType::Elongation
160        } else {
161            LengthType::Replacement
162        }
163    }
164
165    /// The variant with its reading transposed.
166    ///
167    /// # Errors
168    ///
169    /// As [`Stream::transpose`].
170    pub fn transpose(&self, interval: &Interval) -> Result<Self> {
171        Ok(Self {
172            contents: self.contents.transpose(interval)?,
173            ..self.clone()
174        })
175    }
176}
177
178impl From<Variant> for StreamElement {
179    fn from(variant: Variant) -> Self {
180        StreamElement::Variant(Box::new(variant))
181    }
182}
183
184/// When the last thing a stream holds ends, as music21's `highestTime`
185/// has it: each end snapped to the fraction it stands for, as music21
186/// keeps its offsets and lengths as fractions.
187pub fn highest_time(stream: &Stream) -> FloatType {
188    stream
189        .events()
190        .iter()
191        .map(|event| op_frac(event.offset() + length_of(event.element())))
192        .fold(0.0, FloatType::max)
193}
194
195/// How long an element lasts, a stream as [`highest_time`] has it.
196fn length_of(element: &StreamElement) -> FloatType {
197    match element {
198        StreamElement::Stream(inner) => highest_time(inner),
199        other => other.quarter_length(),
200    }
201}
202
203fn variant_error(message: impl Into<String>) -> Error {
204    Error::Variant(message.into())
205}
206
207/// Where each leaf of a stream went, composed with where they went next.
208fn then(first: Vec<Option<usize>>, next: &[Option<usize>]) -> Vec<Option<usize>> {
209    first
210        .into_iter()
211        .map(|place| place.and_then(|at| next.get(at).copied().flatten()))
212        .collect()
213}
214
215/// Every leaf of a stream where it was.
216fn unmoved(stream: &Stream) -> Vec<Option<usize>> {
217    (0..stream.leaf_total()).map(Some).collect()
218}
219
220/// Whether an element is one of a class, by music21's name for it.
221fn is_a(element: &StreamElement, class: &str) -> bool {
222    element.is_instance(class)
223}
224
225/// music21's `GeneralNote`: a note, chord or rest of any kind.
226fn is_general_note(element: &StreamElement) -> bool {
227    is_a(element, "GeneralNote")
228}
229
230fn is_measure(element: &StreamElement) -> bool {
231    matches!(element, StreamElement::Stream(inner) if inner.kind() == StreamKind::Measure)
232}
233
234fn measure_number(element: &StreamElement) -> Option<IntegerType> {
235    match element {
236        StreamElement::Stream(inner) if inner.kind() == StreamKind::Measure => Some(inner.number()),
237        _ => None,
238    }
239}
240
241fn set_measure_number(element: &mut StreamElement, number: IntegerType) {
242    if let StreamElement::Stream(inner) = element
243        && inner.kind() == StreamKind::Measure
244    {
245        inner.set_number(number);
246    }
247}
248
249/// music21's `getElementsByOffset`, as the variant functions call it --
250/// each element starting in the span, and none for having started before
251/// it -- for an element at `offset` lasting `length`. With no end, the span
252/// is the one offset.
253fn in_span(
254    offset: FloatType,
255    length: FloatType,
256    start: FloatType,
257    end: Option<FloatType>,
258    include_end: bool,
259) -> bool {
260    let start = op_frac(start);
261    let (end, zero_length_search) = match end {
262        None => (start, true),
263        Some(end) => {
264            let end = op_frac(end);
265            (end, end <= start)
266        }
267    };
268    if offset > end {
269        return false;
270    }
271    if op_frac(offset + length) < start {
272        return false;
273    }
274    if zero_length_search && length == 0.0 {
275        return true;
276    }
277    if offset < start {
278        return false;
279    }
280    !(!include_end && offset == end)
281}
282
283// --------------------------------------------------------------- site
284
285/// One element of a stream being worked on, known by an id that stays with
286/// it however it moves, with the index it stood at in the stream it came
287/// from, if it came from it.
288#[derive(Clone, Debug)]
289struct Held {
290    id: usize,
291    origin: Option<usize>,
292    order: usize,
293    offset: FloatType,
294    element: StreamElement,
295}
296
297/// A stream being worked on as music21 works on one in place: elements
298/// taken out and put in, each found again by its id, kept in the order
299/// music21 sorts them in -- by offset, class, grace notes first, and the
300/// order they were put in.
301#[derive(Clone, Debug)]
302struct Site {
303    held: Vec<Held>,
304    next: usize,
305}
306
307impl Site {
308    fn of(stream: &Stream) -> Self {
309        let held: Vec<Held> = stream
310            .events()
311            .iter()
312            .enumerate()
313            .map(|(index, event)| Held {
314                id: index,
315                origin: Some(index),
316                order: index,
317                offset: event.offset(),
318                element: event.element().clone(),
319            })
320            .collect();
321        let next = held.len();
322        let mut site = Self { held, next };
323        site.sort();
324        site
325    }
326
327    fn sort(&mut self) {
328        let grace = |held: &Held| held.element.duration().is_some_and(Duration::is_grace);
329        self.held.sort_by(|left, right| {
330            left.offset
331                .total_cmp(&right.offset)
332                .then(
333                    left.element
334                        .class_sort_order()
335                        .cmp(&right.element.class_sort_order()),
336                )
337                .then(grace(right).cmp(&grace(left)))
338                .then(left.order.cmp(&right.order))
339        });
340    }
341
342    fn get(&self, id: usize) -> Option<&Held> {
343        self.held.iter().find(|held| held.id == id)
344    }
345
346    fn get_mut(&mut self, id: usize) -> Option<&mut Held> {
347        self.held.iter_mut().find(|held| held.id == id)
348    }
349
350    fn offset(&self, id: usize) -> Result<FloatType> {
351        self.get(id)
352            .map(|held| held.offset)
353            .ok_or_else(|| variant_error("the element is not in the stream"))
354    }
355
356    fn variant(&self, id: usize) -> Result<&Variant> {
357        match self.get(id).map(|held| &held.element) {
358            Some(StreamElement::Variant(variant)) => Ok(variant),
359            _ => Err(variant_error("Variant not found in stream")),
360        }
361    }
362
363    fn variant_mut(&mut self, id: usize) -> Result<&mut Variant> {
364        match self.get_mut(id).map(|held| &mut held.element) {
365            Some(StreamElement::Variant(variant)) => Ok(variant),
366            _ => Err(variant_error("Variant not found in stream")),
367        }
368    }
369
370    /// Puts in a new element, after anything already here that sorts
371    /// alike, and answers its id.
372    fn insert(&mut self, offset: FloatType, element: StreamElement) -> usize {
373        let id = self.next;
374        self.next += 1;
375        self.held.push(Held {
376            id,
377            origin: None,
378            order: id,
379            offset: op_frac(offset),
380            element,
381        });
382        self.sort();
383        id
384    }
385
386    /// Puts back an element taken out, at a new offset, after anything here
387    /// that sorts alike.
388    fn reinsert(&mut self, mut held: Held, offset: FloatType) {
389        held.offset = op_frac(offset);
390        held.order = self.next;
391        self.next += 1;
392        self.held.push(held);
393        self.sort();
394    }
395
396    fn remove(&mut self, id: usize) -> Option<Held> {
397        let at = self.held.iter().position(|held| held.id == id)?;
398        Some(self.held.remove(at))
399    }
400
401    /// When the last element ends: music21's `highestTime`.
402    fn highest_time(&self) -> FloatType {
403        self.held
404            .iter()
405            .map(|held| op_frac(held.offset + length_of(&held.element)))
406            .fold(0.0, FloatType::max)
407    }
408
409    /// The ids of the elements starting in a span, in order.
410    fn in_span(&self, start: FloatType, end: Option<FloatType>, include_end: bool) -> Vec<usize> {
411        self.held
412            .iter()
413            .filter(|held| {
414                in_span(
415                    held.offset,
416                    length_of(&held.element),
417                    start,
418                    end,
419                    include_end,
420                )
421            })
422            .map(|held| held.id)
423            .collect()
424    }
425
426    /// The ids of the variants, in order.
427    fn variants(&self) -> Vec<usize> {
428        self.held
429            .iter()
430            .filter(|held| matches!(held.element, StreamElement::Variant(_)))
431            .map(|held| held.id)
432            .collect()
433    }
434
435    /// The ids of the measures, in order.
436    fn measures(&self) -> Vec<usize> {
437        self.held
438            .iter()
439            .filter(|held| is_measure(&held.element))
440            .map(|held| held.id)
441            .collect()
442    }
443
444    /// The stream as worked on: `base` holding what is here now, its
445    /// spanners moved with what they name. The answer is also where each of
446    /// `base`'s leaves went.
447    fn finish(self, mut base: Stream) -> (Stream, Vec<Option<usize>>) {
448        let events = self
449            .held
450            .into_iter()
451            .map(|held| (StreamEvent::new(held.offset, held.element), held.origin))
452            .collect();
453        let moved = base.replace_events(events);
454        (base, moved)
455    }
456}
457
458/// Puts an element in a variant's reading after what sorts alike there.
459fn put(contents: &mut Stream, offset: FloatType, element: StreamElement) {
460    contents.insert_sorted(vec![StreamEvent::new(op_frac(offset), element)]);
461}
462
463/// Moves everything in a variant's reading later by `shift`.
464fn shift_contents(contents: &mut Stream, shift: FloatType) {
465    let events: Vec<(StreamEvent, Option<usize>)> = contents
466        .events()
467        .iter()
468        .enumerate()
469        .map(|(index, event)| {
470            (
471                StreamEvent::new(op_frac(event.offset() + shift), event.element().clone()),
472                Some(index),
473            )
474        })
475        .collect();
476    contents.replace_events(events);
477}
478
479// -------------------------------------------------------- replacement
480
481/// What a variant at `id` stands in for among a site's elements, each with
482/// its offset in music21's answer, in the order music21 sorts them: see
483/// [`replaced_elements`].
484fn replaced(
485    site: &Site,
486    id: usize,
487    class_list: &[&str],
488    keep_original_offsets: bool,
489    include_spacers: bool,
490) -> Result<Vec<(usize, FloatType)>> {
491    let variant = site.variant(id)?;
492    let start = site.offset(id)?;
493    let spacer = if include_spacers {
494        variant
495            .contents
496            .events()
497            .iter()
498            .find_map(|event| match event.element() {
499                StreamElement::Rest(rest) if rest.hidden() => {
500                    Some(rest.duration().quarter_length())
501                }
502                _ => None,
503            })
504            .ok_or_else(|| variant_error("'NoneType' object has no attribute 'duration'"))?
505    } else {
506        0.0
507    };
508    let mut wanted: Vec<&str> = variant
509        .contents
510        .events()
511        .iter()
512        .map(|event| event.element().music21_classes()[0])
513        .collect();
514    wanted.extend_from_slice(class_list);
515    let of_class = |held_id: usize| {
516        site.get(held_id)
517            .is_some_and(|held| wanted.iter().any(|class| is_a(&held.element, class)))
518    };
519    let mut found: Vec<(usize, FloatType)> = Vec::new();
520    match variant.length_type() {
521        LengthType::Replacement | LengthType::Elongation => {
522            let end = start + variant.replacement_quarter_length() + spacer;
523            for held_id in site.in_span(start, Some(end), false) {
524                if of_class(held_id) {
525                    found.push((held_id, site.offset(held_id)?));
526                }
527            }
528        }
529        LengthType::Deletion => {
530            let middle = start + variant.contained_highest_time();
531            let end = start + variant.replacement_quarter_length();
532            for held_id in site.in_span(start, Some(middle), false) {
533                if of_class(held_id) {
534                    found.push((held_id, site.offset(held_id)?));
535                }
536            }
537            for held_id in site.in_span(middle, Some(end), false) {
538                if found.iter().any(|(seen, _)| *seen == held_id) {
539                    return Err(variant_error("the object is already found in this Stream"));
540                }
541                found.push((held_id, op_frac(middle - start + site.offset(held_id)?)));
542            }
543        }
544    }
545    found.retain(|(held_id, _)| *held_id != id);
546    if !keep_original_offsets {
547        for (_, offset) in &mut found {
548            *offset = op_frac(*offset - start);
549        }
550    }
551    // Sorted in the stream music21 answers with, which they went into in
552    // this order.
553    let grace = |held_id: usize| {
554        site.get(held_id)
555            .is_some_and(|held| held.element.duration().is_some_and(Duration::is_grace))
556    };
557    let sort_order = |held_id: usize| {
558        site.get(held_id)
559            .map_or(0, |held| held.element.class_sort_order())
560    };
561    found.sort_by(|left, right| {
562        left.1
563            .total_cmp(&right.1)
564            .then(sort_order(left.0).cmp(&sort_order(right.0)))
565            .then(grace(right.0).cmp(&grace(left.0)))
566    });
567    Ok(found)
568}
569
570/// What the variant at event `variant` of a stream stands in for: the
571/// elements of the stream of the classes of what the variant holds (and of
572/// `class_list`) starting where it does and within its replacement length,
573/// at their offsets from the variant's unless `keep_original_offsets`:
574/// music21's `replacedElements`. With `include_spacers`, the span goes on
575/// by as long as the first hidden rest the variant holds.
576///
577/// A variant shorter than what it replaces stands in, past what it holds,
578/// for everything there whatever its class, which music21 puts that much
579/// later again.
580///
581/// # Errors
582///
583/// No variant at `variant`, or with `include_spacers` no hidden rest in it.
584pub fn replaced_elements(
585    stream: &Stream,
586    variant: usize,
587    class_list: &[&str],
588    keep_original_offsets: bool,
589    include_spacers: bool,
590) -> Result<Stream> {
591    let site = Site::of(stream);
592    let found = replaced(
593        &site,
594        variant,
595        class_list,
596        keep_original_offsets,
597        include_spacers,
598    )?;
599    let mut out = Stream::with_kind(stream.kind());
600    let events: Vec<StreamEvent> = found
601        .into_iter()
602        .filter_map(|(id, offset)| {
603            site.get(id)
604                .map(|held| StreamEvent::new(offset, held.element.clone()))
605        })
606        .collect();
607    out.replace_events(events.into_iter().map(|event| (event, None)).collect());
608    Ok(out)
609}
610
611/// Takes out of a stream what the variant at event `variant` stands in for:
612/// music21's `removeReplacedElementsFromStream`.
613///
614/// # Errors
615///
616/// As [`replaced_elements`].
617pub fn remove_replaced_elements_from_stream(
618    stream: &mut Stream,
619    variant: usize,
620    class_list: &[&str],
621) -> Result<()> {
622    let mut site = Site::of(stream);
623    for (id, _) in replaced(&site, variant, class_list, false, false)? {
624        site.remove(id);
625    }
626    let (out, _) = site.finish(stream.clone());
627    *stream = out;
628    Ok(())
629}
630
631// --------------------------------------------------------------- hashes
632
633/// The notes, rests and chords a stream holds itself.
634fn own_notes(stream: &Stream) -> Vec<crate::search::Searched<'_>> {
635    iterated(stream)
636        .into_iter()
637        .filter(|found| is_general_note(found.element))
638        .collect()
639}
640
641/// Each measure of a stream as the text of its notes and rests:
642/// music21's `getMeasureHashes`.
643pub fn measure_hashes(stream: &Stream) -> Vec<String> {
644    stream
645        .measures()
646        .into_iter()
647        .map(|measure| translate_stream_to_string(&own_notes(measure)).text)
648        .collect()
649}
650
651fn measure_hash(measure: &Stream) -> String {
652    translate_stream_to_string(&own_notes(measure)).text
653}
654
655/// Python's `difflib` opcodes between two lists of items compared equal or
656/// not.
657fn opcodes_of<'a, T: PartialEq>(a: &'a [T], b: &'a [T]) -> Vec<difflib::Opcode> {
658    // Each item stands for the first item equal to it.
659    let mut seen: Vec<&'a T> = Vec::new();
660    let mut id = |item: &'a T| match seen.iter().position(|known| *known == item) {
661        Some(at) => at,
662        None => {
663            seen.push(item);
664            seen.len() - 1
665        }
666    };
667    let a: Vec<usize> = a.iter().map(&mut id).collect();
668    let b: Vec<usize> = b.iter().map(&mut id).collect();
669    difflib::opcodes(&a, &b)
670}
671
672// ------------------------------------------------------------ measures
673
674/// The event indices of a stream's own measures numbered `start` to `end`,
675/// or from `start` on, counting them from one where every measure is
676/// numbered nought: music21's `measures` and `measure` finding them.
677fn numbered(stream: &Stream, start: IntegerType, end: Option<IntegerType>) -> Vec<usize> {
678    let measures: Vec<(usize, IntegerType)> = stream
679        .events()
680        .iter()
681        .enumerate()
682        .filter_map(|(index, event)| measure_number(event.element()).map(|number| (index, number)))
683        .collect();
684    let numbered = measures.iter().any(|(_, number)| *number != 0);
685    measures
686        .iter()
687        .enumerate()
688        .filter(|(count, (_, number))| {
689            let number = if numbered {
690                *number
691            } else {
692                *count as IntegerType + 1
693            };
694            number >= start && end.is_none_or(|end| number <= end)
695        })
696        .map(|(_, (index, _))| *index)
697        .collect()
698}
699
700/// How long music21's `measures` of those measures lasts: from the start
701/// of the first to the end of the last.
702fn span_length(stream: &Stream, measures: &[usize]) -> FloatType {
703    let Some(&first) = measures.first() else {
704        return 0.0;
705    };
706    let start = stream.events()[first].offset();
707    measures
708        .iter()
709        .map(|&index| {
710            let event = &stream.events()[index];
711            op_frac(op_frac(event.offset() - start) + length_of(event.element()))
712        })
713        .fold(0.0, FloatType::max)
714}
715
716/// The measures, as music21's `measures` holds them: from the first's
717/// offset on.
718fn measures_stream(stream: &Stream, measures: &[usize]) -> Stream {
719    let mut out = Stream::new();
720    let Some(&first) = measures.first() else {
721        return out;
722    };
723    let start = stream.events()[first].offset();
724    for &index in measures {
725        let event = &stream.events()[index];
726        put(
727            &mut out,
728            op_frac(event.offset() - start),
729            event.element().clone(),
730        );
731    }
732    out
733}
734
735fn no_such_measure() -> Error {
736    variant_error("'NoneType' object has no attribute 'getOffsetBySite'")
737}
738
739// ---------------------------------------------------------- add_variant
740
741/// The variant [`add_variant`] adds.
742fn made_variant(
743    start_offset: FloatType,
744    contents: Option<&Stream>,
745    variant_name: Option<&str>,
746    variant_groups: Option<&[String]>,
747    replacement_quarter_length: Option<FloatType>,
748) -> Variant {
749    let mut variant = Variant::new();
750    if let Some(groups) = variant_groups {
751        variant.groups = groups.to_vec();
752    }
753    if let Some(name) = variant_name {
754        variant.groups.push(name.to_string());
755    }
756    variant.replacement_quarter_length = replacement_quarter_length;
757    match contents {
758        None => {}
759        Some(stream) if stream.kind() == StreamKind::Measure => {
760            variant
761                .contents
762                .push(StreamElement::Stream(Box::new(stream.clone())));
763        }
764        Some(stream) => {
765            let measures = stream.measures();
766            if measures.is_empty() {
767                for event in stream.events() {
768                    put(
769                        &mut variant.contents,
770                        event.offset() + start_offset,
771                        event.element().clone(),
772                    );
773                }
774            } else {
775                for measure in measures {
776                    variant
777                        .contents
778                        .push(StreamElement::Stream(Box::new(measure.clone())));
779                }
780            }
781        }
782    }
783    variant
784}
785
786/// Adds a variant to a stream at `start_offset`, holding `contents`: a
787/// measure, the measures of a stream, or, for a stream with none, its
788/// elements -- each put as far after the variant's start as `start_offset`,
789/// as music21 puts them. The variant is in `variant_groups` and
790/// `variant_name`, and stands in for `replacement_quarter_length`, or for
791/// as long as it lasts: music21's `addVariant`.
792///
793/// ```
794/// use music21_rs::tinynotation::from_tiny_notation;
795/// use music21_rs::variant::add_variant;
796///
797/// let mut line = from_tiny_notation("4/4 c4 d e f g1")?;
798/// let other = from_tiny_notation("4/4 c4 d e g")?;
799/// add_variant(&mut line, 0.0, Some(other.measures()[0]), Some("draft"), None, None);
800/// assert_eq!(line.events().iter().filter(|event| matches!(
801///     event.element(),
802///     music21_rs::StreamElement::Variant(_)
803/// )).count(), 1);
804/// # Ok::<(), music21_rs::Error>(())
805/// ```
806pub fn add_variant(
807    stream: &mut Stream,
808    start_offset: FloatType,
809    contents: Option<&Stream>,
810    variant_name: Option<&str>,
811    variant_groups: Option<&[String]>,
812    replacement_quarter_length: Option<FloatType>,
813) {
814    added(
815        stream,
816        start_offset,
817        contents,
818        variant_name,
819        variant_groups,
820        replacement_quarter_length,
821    );
822}
823
824fn added(
825    stream: &mut Stream,
826    start_offset: FloatType,
827    contents: Option<&Stream>,
828    variant_name: Option<&str>,
829    variant_groups: Option<&[String]>,
830    replacement_quarter_length: Option<FloatType>,
831) -> Vec<Option<usize>> {
832    let variant = made_variant(
833        start_offset,
834        contents,
835        variant_name,
836        variant_groups,
837        replacement_quarter_length,
838    );
839    stream.insert_sorted(vec![StreamEvent::new(
840        start_offset,
841        StreamElement::from(variant),
842    )])
843}
844
845// --------------------------------------------------------------- merges
846
847/// Merges another version of a stream into a copy of it as variants named
848/// `variant_name`: a score part by part ([`merge_variant_scores`]), a
849/// stream of measures measure by measure
850/// ([`merge_variant_measure_streams`]), or notes and rests of the same
851/// length note by note ([`merge_variants_equal_duration`]): music21's
852/// `mergeVariants`.
853///
854/// # Errors
855///
856/// As each of those, or a stream none of them merges.
857pub fn merge_variants(x: &Stream, y: &Stream, variant_name: &str) -> Result<Stream> {
858    if x.kind() == StreamKind::Score {
859        merge_variant_scores(x, y, variant_name)
860    } else if !x.measures().is_empty() {
861        merge_variant_measure_streams(x, y, variant_name)
862    } else if x
863        .events()
864        .iter()
865        .any(|event| is_general_note(event.element()))
866        && highest_time(x) == highest_time(y)
867    {
868        merge_variants_equal_duration(&[x, y], &[variant_name])
869    } else {
870        Err(variant_error(
871            "Could not determine what merging method to use. Try using a more specific merging function.",
872        ))
873    }
874}
875
876/// Merges another version of a score into a copy of it, each part into the
877/// part at its place, as [`merge_variant_measure_streams`] merges them:
878/// music21's `mergeVariantScores`.
879///
880/// # Errors
881///
882/// Scores of different numbers of parts, or as
883/// [`merge_variant_measure_streams`].
884pub fn merge_variant_scores(a: &Stream, v: &Stream, variant_name: &str) -> Result<Stream> {
885    let parts = |score: &Stream| -> Vec<usize> {
886        score
887            .events()
888            .iter()
889            .enumerate()
890            .filter(|(_, event)| {
891                matches!(event.element(), StreamElement::Stream(inner)
892                    if matches!(inner.kind(), StreamKind::Part | StreamKind::PartStaff))
893            })
894            .map(|(index, _)| index)
895            .collect()
896    };
897    let (ours, theirs) = (parts(a), parts(v));
898    if ours.len() != theirs.len() {
899        return Err(variant_error(
900            "These scores do not have the same number of parts and cannot be merged.",
901        ));
902    }
903    let mut out = a.clone();
904    for (&part, &other) in ours.iter().zip(&theirs) {
905        let StreamElement::Stream(y) = v.events()[other].element() else {
906            continue;
907        };
908        out.edit_nested(&[part], |stream| {
909            match merge_measure_streams_into(stream, y, variant_name) {
910                Ok(moved) => (Ok(()), moved),
911                Err(error) => (Err(error), unmoved(stream)),
912            }
913        })
914        .0?;
915    }
916    Ok(out)
917}
918
919/// Merges another version of a stream of measures into a copy of it: the
920/// measures of the two compared by their notes and rests as `difflib`
921/// compares lists, and a variant added where they differ -- replacing
922/// measures, taking them out or putting new ones in: music21's
923/// `mergeVariantMeasureStreams`.
924///
925/// Measures are found by their numbers counted from one, as music21 finds
926/// them, so a stream not numbered from one finds others than those that
927/// differ, or none.
928///
929/// # Errors
930///
931/// A measure music21 looks for by number that is not there.
932pub fn merge_variant_measure_streams(x: &Stream, y: &Stream, variant_name: &str) -> Result<Stream> {
933    let mut out = x.clone();
934    merge_measure_streams_into(&mut out, y, variant_name)?;
935    Ok(out)
936}
937
938fn merge_measure_streams_into(
939    out: &mut Stream,
940    y: &Stream,
941    variant_name: &str,
942) -> Result<Vec<Option<usize>>> {
943    let mut moved = unmoved(out);
944    let regions = opcodes_of(&measure_hashes(out), &measure_hashes(y));
945    for region in regions {
946        let (x_start, x_end) = (region.i1 as IntegerType, region.i2 as IntegerType);
947        let (y_start, y_end) = (region.j1 as IntegerType, region.j2 as IntegerType);
948        let start_offset = if region.i1 >= out.measures().len() {
949            highest_time(out)
950        } else {
951            let index = *numbered(out, x_start + 1, Some(x_start + 1))
952                .first()
953                .ok_or_else(no_such_measure)?;
954            out.events()[index].offset()
955        };
956        let (contents, length) = match region.tag {
957            difflib::OpcodeTag::Equal => continue,
958            difflib::OpcodeTag::Replace => (
959                Some(measures_stream(y, &numbered(y, y_start + 1, Some(y_end)))),
960                span_length(out, &numbered(out, x_start + 1, Some(x_end))),
961            ),
962            difflib::OpcodeTag::Delete => (
963                None,
964                span_length(out, &numbered(out, x_start + 1, Some(x_end))),
965            ),
966            difflib::OpcodeTag::Insert => (
967                Some(measures_stream(y, &numbered(y, y_start + 1, Some(y_end)))),
968                0.0,
969            ),
970        };
971        let step = added(
972            out,
973            start_offset,
974            contents.as_ref(),
975            Some(variant_name),
976            None,
977            Some(length),
978        );
979        moved = then(moved, &step);
980    }
981    Ok(moved)
982}
983
984/// Merges other versions of a stream, each as long as it, into a copy of
985/// it: part by part and measure by measure where it has them, each stretch
986/// of notes and rests that differs a variant, named by `variant_names` in
987/// turn: music21's `mergeVariantsEqualDuration`.
988///
989/// # Errors
990///
991/// A version of another length, one with fewer parts or measures, or a
992/// stream holding measures or parts where notes are compared.
993pub fn merge_variants_equal_duration(
994    streams: &[&Stream],
995    variant_names: &[&str],
996) -> Result<Stream> {
997    let Some((first, others)) = streams.split_first() else {
998        return Err(variant_error("list index out of range"));
999    };
1000    let mut out = (*first).clone();
1001    let mut names: Vec<Option<String>> = vec![None];
1002    names.extend(variant_names.iter().map(|name| Some(name.to_string())));
1003    names.resize(streams.len(), None);
1004    let pairs: Vec<(&Stream, Option<String>)> = others
1005        .iter()
1006        .copied()
1007        .zip(names.into_iter().skip(1))
1008        .collect();
1009    equal_duration_into(&mut out, &pairs)?;
1010    Ok(out)
1011}
1012
1013fn equal_duration_into(
1014    out: &mut Stream,
1015    others: &[(&Stream, Option<String>)],
1016) -> Result<Vec<Option<usize>>> {
1017    let mut moved = unmoved(out);
1018    let out_of_range = || variant_error("list index out of range");
1019    for (other, name) in others {
1020        if highest_time(out) != highest_time(other) {
1021            return Err(variant_error("cannot merge streams of different lengths"));
1022        }
1023        let name = name.as_deref();
1024        let part_events: Vec<usize> = out
1025            .events()
1026            .iter()
1027            .enumerate()
1028            .filter(|(_, event)| {
1029                matches!(event.element(), StreamElement::Stream(inner)
1030                    if matches!(inner.kind(), StreamKind::Part | StreamKind::PartStaff))
1031            })
1032            .map(|(index, _)| index)
1033            .collect();
1034        let step = if part_events.is_empty() {
1035            let theirs = other.measures();
1036            let ours = numbered_all(out);
1037            if ours.is_empty() {
1038                merged_into(out, &[], other, name)?
1039            } else {
1040                let mut step = unmoved(out);
1041                for (j, &index) in ours.iter().enumerate() {
1042                    let measure = theirs.get(j).ok_or_else(out_of_range)?;
1043                    step = then(step, &merged_into(out, &[index], measure, name)?);
1044                }
1045                step
1046            }
1047        } else {
1048            let their_parts = other.parts();
1049            let mut step = unmoved(out);
1050            for (i, &part_index) in part_events.iter().enumerate() {
1051                let their_part = their_parts.get(i).ok_or_else(out_of_range)?;
1052                let StreamElement::Stream(part) = out.events()[part_index].element() else {
1053                    continue;
1054                };
1055                let ours = numbered_all(part);
1056                if ours.is_empty() {
1057                    step = then(step, &merged_into(out, &[part_index], their_part, name)?);
1058                } else {
1059                    let theirs = their_part.measures();
1060                    for (j, &index) in ours.iter().enumerate() {
1061                        let measure = theirs.get(j).ok_or_else(out_of_range)?;
1062                        step = then(
1063                            step,
1064                            &merged_into(out, &[part_index, index], measure, name)?,
1065                        );
1066                    }
1067                }
1068            }
1069            step
1070        };
1071        moved = then(moved, &step);
1072    }
1073    Ok(moved)
1074}
1075
1076/// The event indices of a stream's own measures.
1077fn numbered_all(stream: &Stream) -> Vec<usize> {
1078    stream
1079        .events()
1080        .iter()
1081        .enumerate()
1082        .filter(|(_, event)| is_measure(event.element()))
1083        .map(|(index, _)| index)
1084        .collect()
1085}
1086
1087/// [`merge_notes`] into the stream at `path` within `out`.
1088fn merged_into(
1089    out: &mut Stream,
1090    path: &[usize],
1091    other: &Stream,
1092    name: Option<&str>,
1093) -> Result<Vec<Option<usize>>> {
1094    let (result, moved) = out.edit_nested(path, |stream| match merge_notes(stream, other, name) {
1095        Ok(moved) => (Ok(()), moved),
1096        Err(error) => (Err(error), unmoved(stream)),
1097    });
1098    result.map(|()| moved)
1099}
1100
1101fn holds_measures_or_parts(stream: &Stream) -> bool {
1102    stream.events().iter().any(|event| {
1103        matches!(event.element(), StreamElement::Stream(inner)
1104            if matches!(inner.kind(), StreamKind::Measure | StreamKind::Part | StreamKind::PartStaff))
1105    })
1106}
1107
1108/// music21's `_mergeVariants`: the notes and rests of two streams of the
1109/// same length walked together, and each stretch where `b`'s differ from
1110/// `a`'s, or start where none of `a`'s does, a variant in `a`.
1111fn merge_notes(a: &mut Stream, b: &Stream, name: Option<&str>) -> Result<Vec<Option<usize>>> {
1112    if holds_measures_or_parts(a) || holds_measures_or_parts(b) {
1113        return Err(variant_error(
1114            "_mergeVariants cannot merge streams which contain measures or parts.",
1115        ));
1116    }
1117    if highest_time(a) != highest_time(b) {
1118        return Err(variant_error(
1119            "_mergeVariants cannot merge streams which are of different lengths",
1120        ));
1121    }
1122    let notes = |stream: &Stream| -> Vec<StreamEvent> {
1123        stream
1124            .flatten()
1125            .events()
1126            .iter()
1127            .filter(|event| is_general_note(event.element()))
1128            .cloned()
1129            .collect()
1130    };
1131    let (a_notes, b_notes) = (notes(a), notes(b));
1132    let mut moved = unmoved(a);
1133    let (mut i, mut j) = (0, 0);
1134    let mut in_variant = false;
1135    let mut buffer: Vec<&StreamEvent> = Vec::new();
1136    let mut variant_start = 0.0;
1137    let mut insert = |a: &mut Stream, buffer: &[&StreamEvent], start: FloatType| {
1138        let mut variant = Variant::new();
1139        for event in buffer {
1140            put(
1141                &mut variant.contents,
1142                event.offset() - start,
1143                event.element().clone(),
1144            );
1145        }
1146        if let Some(name) = name {
1147            variant.groups.push(name.to_string());
1148        }
1149        let step = a.insert_sorted(vec![StreamEvent::new(start, StreamElement::from(variant))]);
1150        moved = then(std::mem::take(&mut moved), &step);
1151    };
1152    while i < a_notes.len() && j < b_notes.len() {
1153        let (ours, theirs) = (&a_notes[i], &b_notes[j]);
1154        if ours.offset() == theirs.offset() {
1155            if !equal(ours.element(), theirs.element()) {
1156                if !in_variant {
1157                    variant_start = theirs.offset();
1158                    in_variant = true;
1159                    buffer = vec![theirs];
1160                } else {
1161                    buffer.push(theirs);
1162                }
1163            } else if in_variant {
1164                insert(a, &buffer, variant_start);
1165                in_variant = false;
1166                buffer.clear();
1167            }
1168            i += 1;
1169            j += 1;
1170        } else if ours.offset() > theirs.offset() {
1171            if !in_variant {
1172                variant_start = theirs.offset();
1173                buffer = vec![theirs];
1174                in_variant = true;
1175            } else {
1176                buffer.push(theirs);
1177            }
1178            j += 1;
1179        } else {
1180            i += 1;
1181        }
1182    }
1183    if in_variant {
1184        insert(a, &buffer, variant_start);
1185    }
1186    Ok(moved)
1187}
1188
1189/// Merges the measures of an ossia part that hold notes into a copy of a
1190/// part, each as a variant named `ossia_name` where the ossia's measure
1191/// stands -- the measure of the same number, with
1192/// `compare_by_measure_number`, or else at the same offset -- or, with
1193/// `recurse_in_measures`, each stretch of its notes that differs as a
1194/// variant inside the part's measure: music21's `mergePartAsOssia`.
1195///
1196/// # Errors
1197///
1198/// No measure of the part where the ossia has one, or as
1199/// [`merge_variants_equal_duration`].
1200pub fn merge_part_as_ossia(
1201    main: &Stream,
1202    ossia: &Stream,
1203    ossia_name: &str,
1204    compare_by_measure_number: bool,
1205    recurse_in_measures: bool,
1206) -> Result<Stream> {
1207    let mut out = main.clone();
1208    let no_measure = || variant_error("'NoneType' object has no attribute 'highestTime'");
1209    for event in ossia.events() {
1210        let StreamElement::Stream(measure) = event.element() else {
1211            continue;
1212        };
1213        if measure.kind() != StreamKind::Measure
1214            || !measure
1215                .events()
1216                .iter()
1217                .any(|inner| is_a(inner.element(), "NotRest"))
1218        {
1219            continue;
1220        }
1221        if compare_by_measure_number {
1222            let target = numbered(&out, measure.number(), Some(measure.number()))
1223                .first()
1224                .copied();
1225            if recurse_in_measures {
1226                let index = target.ok_or_else(no_measure)?;
1227                let pairs = [(&**measure, Some(ossia_name.to_string()))];
1228                out.edit_nested(&[index], |stream| {
1229                    match equal_duration_into(stream, &pairs) {
1230                        Ok(moved) => (Ok(()), moved),
1231                        Err(error) => (Err(error), unmoved(stream)),
1232                    }
1233                })
1234                .0?;
1235            } else {
1236                let index = target.ok_or_else(no_such_measure)?;
1237                let offset = out.events()[index].offset();
1238                added(
1239                    &mut out,
1240                    offset,
1241                    Some(measure),
1242                    Some(ossia_name),
1243                    None,
1244                    None,
1245                );
1246            }
1247        } else {
1248            let offset = event.offset();
1249            if recurse_in_measures {
1250                let index = out
1251                    .events()
1252                    .iter()
1253                    .enumerate()
1254                    .find(|(_, held)| {
1255                        is_measure(held.element())
1256                            && at_offset(
1257                                held.offset(),
1258                                length_of(held.element()),
1259                                Exact::held(offset),
1260                            )
1261                    })
1262                    .map(|(index, _)| index)
1263                    .ok_or_else(no_measure)?;
1264                let pairs = [(&**measure, Some(ossia_name.to_string()))];
1265                out.edit_nested(&[index], |stream| {
1266                    match equal_duration_into(stream, &pairs) {
1267                        Ok(moved) => (Ok(()), moved),
1268                        Err(error) => (Err(error), unmoved(stream)),
1269                    }
1270                })
1271                .0?;
1272            } else {
1273                added(
1274                    &mut out,
1275                    offset,
1276                    Some(measure),
1277                    Some(ossia_name),
1278                    None,
1279                    None,
1280                );
1281            }
1282        }
1283    }
1284    Ok(out)
1285}
1286
1287// --------------------------------------------------------------- refine
1288
1289/// One choice on the way to music21's `_getBestListAndScore`: for each
1290/// element of the variant, which element of the region it is, or none for a
1291/// measure the variant adds, and how bad the match is.
1292#[allow(clippy::too_many_arguments)]
1293fn best_list(
1294    x: &[&StreamElement],
1295    y: &[&StreamElement],
1296    badness: &mut HashMap<(isize, isize, bool), FloatType>,
1297    lists: &mut HashMap<(isize, isize, bool), Vec<Option<usize>>>,
1298    is_none: bool,
1299    x_index: isize,
1300    y_index: isize,
1301) -> Result<(Vec<Option<usize>>, FloatType)> {
1302    let key = (x_index, y_index, is_none);
1303    if y_index >= y.len() as isize {
1304        lists.insert(key, Vec::new());
1305        badness.insert(key, 0.0);
1306        return Ok((Vec::new(), 0.0));
1307    }
1308    if let Some(&bad) = badness.get(&key) {
1309        return Ok((lists.get(&key).cloned().unwrap_or_default(), bad));
1310    }
1311    let similarity = if x_index == -1 && y_index == -1 {
1312        0.0
1313    } else if is_none {
1314        0.5
1315    } else {
1316        diff_score(x[x_index as usize], y[y_index as usize])?
1317    };
1318    let (mut best_score, mut best_normalized, mut best) = (1.0, 1.0, Vec::new());
1319    let mut consider = |(list, bad): (Vec<Option<usize>>, FloatType)| {
1320        let normalized = if list.is_empty() {
1321            0.0
1322        } else {
1323            bad / list.len() as FloatType
1324        };
1325        if normalized <= best_normalized {
1326            best_score = bad;
1327            best_normalized = normalized;
1328            best = list;
1329        }
1330    };
1331    consider(best_list(x, y, badness, lists, true, x_index, y_index + 1)?);
1332    for k in (x_index + 1)..(x.len() as isize) {
1333        consider(best_list(x, y, badness, lists, false, k, y_index + 1)?);
1334    }
1335    let mut list = best;
1336    if is_none {
1337        list.insert(0, None);
1338    } else if x_index != -1 {
1339        list.insert(0, Some(x_index as usize));
1340    }
1341    let bad = best_score + similarity;
1342    badness.insert(key, bad);
1343    lists.insert(key, list.clone());
1344    Ok((list, bad))
1345}
1346
1347/// music21's `_diffScore`: nought for two measures of the same notes and
1348/// rests and 0.4 for others, and a thousandth for each number apart.
1349fn diff_score(x: &StreamElement, y: &StreamElement) -> Result<FloatType> {
1350    let (StreamElement::Stream(x), StreamElement::Stream(y)) = (x, y) else {
1351        return Err(variant_error("object has no attribute 'notesAndRests'"));
1352    };
1353    if x.kind() != StreamKind::Measure || y.kind() != StreamKind::Measure {
1354        return Err(variant_error("'Stream' object has no attribute 'number'"));
1355    }
1356    let base = if measure_hash(x) == measure_hash(y) {
1357        0.0
1358    } else {
1359        0.4
1360    };
1361    Ok(base + FloatType::from(x.number() - y.number()) * 0.001)
1362}
1363
1364/// Refines the variant at event `variant` of a stream measure by measure,
1365/// as music21's `refineVariant` does in place: the measures it replaces
1366/// matched with the measures it holds, and where a run of them match, each
1367/// stretch of notes that differs a variant inside the stream's measure.
1368/// The variant itself is taken out.
1369///
1370/// music21 adds the runs that do not match to a copy it then lets go, so
1371/// they are not kept here either. The measures of a matching run are found
1372/// by their numbers counted from one, as music21 finds them, and the
1373/// variant's groups name the first run's variants only: music21 puts a
1374/// `None` before them for each run.
1375///
1376/// # Errors
1377///
1378/// No variant at `variant`; something other than a measure in what it
1379/// replaces or holds; or as [`merge_variants_equal_duration`].
1380pub fn refine_variant(stream: &mut Stream, variant: usize) -> Result<()> {
1381    let site = Site::of(stream);
1382    let held = site.variant(variant)?.clone();
1383    let region = replaced(&site, variant, &[], false, false)?;
1384    let region_elements: Vec<&StreamElement> = region
1385        .iter()
1386        .filter_map(|(id, _)| site.get(*id).map(|held| &held.element))
1387        .collect();
1388    let variant_elements: Vec<&StreamElement> = held
1389        .contents
1390        .events()
1391        .iter()
1392        .map(StreamEvent::element)
1393        .collect();
1394    let (chosen, _) = best_list(
1395        &region_elements,
1396        &variant_elements,
1397        &mut HashMap::new(),
1398        &mut HashMap::new(),
1399        false,
1400        -1,
1401        -1,
1402    )?;
1403    let ours: Vec<Option<usize>> = (0..region.len()).map(Some).collect();
1404    // The region as the stream music21 answers with: what each element is
1405    // in the stream.
1406    let mut region_stream = Stream::new();
1407    region_stream.replace_events(
1408        region
1409            .iter()
1410            .filter_map(|(id, offset)| {
1411                site.get(*id)
1412                    .map(|held| (StreamEvent::new(*offset, held.element.clone()), None))
1413            })
1414            .collect(),
1415    );
1416    let mut names: Vec<Option<String>> = held.groups.iter().cloned().map(Some).collect();
1417    for step in opcodes_of(&ours, &chosen) {
1418        if region.get(step.i1).is_none() {
1419            return Err(variant_error("index out of range"));
1420        }
1421        if step.tag != difflib::OpcodeTag::Equal {
1422            continue;
1423        }
1424        let ours_matched = numbered(
1425            &region_stream,
1426            step.i1 as IntegerType + 1,
1427            Some(step.i2 as IntegerType),
1428        );
1429        let theirs_matched = numbered(
1430            &held.contents,
1431            step.j1 as IntegerType + 1,
1432            Some(step.j2 as IntegerType),
1433        );
1434        // music21's names: a `None` put first and the list cut to two.
1435        names.insert(0, None);
1436        names.resize(2, None);
1437        let name = names[1].clone();
1438        if span_length(&region_stream, &ours_matched)
1439            != span_length(&held.contents, &theirs_matched)
1440        {
1441            return Err(variant_error("cannot merge streams of different lengths"));
1442        }
1443        if ours_matched.is_empty() {
1444            if !theirs_matched.is_empty() {
1445                return Err(variant_error(
1446                    "_mergeVariants cannot merge streams which contain measures or parts.",
1447                ));
1448            }
1449            continue;
1450        }
1451        let theirs: Vec<&Stream> = theirs_matched
1452            .iter()
1453            .filter_map(|&index| held.contents.events()[index].element().as_stream())
1454            .collect();
1455        for (j, &index) in ours_matched.iter().enumerate() {
1456            let measure = theirs
1457                .get(j)
1458                .ok_or_else(|| variant_error("list index out of range"))?;
1459            // The measure is the stream's own: found by the place it came
1460            // from.
1461            let id = region[index].0;
1462            let origin = site
1463                .get(id)
1464                .and_then(|held| held.origin)
1465                .ok_or_else(|| variant_error("the measure is not in the stream"))?;
1466            merged_into(stream, &[origin], measure, name.as_deref())?;
1467        }
1468    }
1469    let mut site = Site::of(stream);
1470    site.remove(variant);
1471    let (out, _) = site.finish(stream.clone());
1472    *stream = out;
1473    Ok(())
1474}
1475
1476// ---------------------------------------------------- replacements made
1477
1478/// Makes each variant of a copy of a stream that only inserts or only
1479/// deletes into one that replaces: an insertion at the start, or a
1480/// deletion anywhere but the end, takes in the element after it, and the
1481/// others the element before it, moving back to start there: music21's
1482/// `makeAllVariantsReplacements`. With `recurse`, the variants of the
1483/// streams the stream holds are made so, and not the stream's own, as
1484/// music21 does; music21's `variantNames` leaves every variant as it is,
1485/// so it is not taken.
1486///
1487/// # Errors
1488///
1489/// A variant with no element before it to take in, or one that cannot
1490/// say what it replaces.
1491pub fn make_all_variants_replacements(stream: &Stream, recurse: bool) -> Result<Stream> {
1492    let mut out = stream.clone();
1493    if recurse {
1494        let mut paths: Vec<Vec<usize>> = Vec::new();
1495        collect_stream_paths(&out, &mut Vec::new(), &mut paths);
1496        for path in paths {
1497            out.edit_nested(&path, |inner| match fix_variants(inner) {
1498                Ok(moved) => (Ok(()), moved),
1499                Err(error) => (Err(error), unmoved(inner)),
1500            })
1501            .0?;
1502        }
1503    } else {
1504        fix_variants(&mut out)?;
1505    }
1506    Ok(out)
1507}
1508
1509/// The paths to every stream a stream holds, a stream before those it
1510/// holds.
1511fn collect_stream_paths(stream: &Stream, path: &mut Vec<usize>, out: &mut Vec<Vec<usize>>) {
1512    for (index, event) in stream.events().iter().enumerate() {
1513        if let StreamElement::Stream(inner) = event.element() {
1514            path.push(index);
1515            out.push(path.clone());
1516            collect_stream_paths(inner, path, out);
1517            path.pop();
1518        }
1519    }
1520}
1521
1522/// The first of the measures, notes and rests of a list of elements, by
1523/// music21's class name.
1524fn first_of_kinds<'a>(
1525    elements: impl IntoIterator<Item = &'a StreamElement>,
1526) -> Option<&'static str> {
1527    elements
1528        .into_iter()
1529        .find(|element| {
1530            ["Measure", "Note", "Rest"]
1531                .iter()
1532                .any(|class| is_a(element, class))
1533        })
1534        .map(|element| element.music21_classes()[0])
1535}
1536
1537/// music21's `_doVariantFixingOnStream`.
1538fn fix_variants(stream: &mut Stream) -> Result<Vec<Option<usize>>> {
1539    #[derive(PartialEq)]
1540    enum Kind {
1541        Insertion,
1542        Deletion,
1543    }
1544    let mut site = Site::of(stream);
1545    for id in site.variants() {
1546        let variant = site.variant(id)?;
1547        let length = variant.replacement_quarter_length();
1548        let kind = match variant.length_type() {
1549            LengthType::Elongation if length == 0.0 => Kind::Insertion,
1550            LengthType::Deletion if variant.contained_highest_time() == 0.0 => Kind::Deletion,
1551            _ => continue,
1552        };
1553        let offset = site.offset(id)?;
1554        let initial = offset == 0.0;
1555        let last = !initial && offset + length == site.highest_time();
1556        let target_length;
1557        if (kind == Kind::Insertion && initial) || (kind == Kind::Deletion && !last) {
1558            let target = next_element(&site, id)?;
1559            let Some(target) = target else {
1560                return Err(variant_error("cannot append None to a Stream"));
1561            };
1562            let held = site
1563                .get_mut(target)
1564                .ok_or_else(|| variant_error("the element is not in the stream"))?;
1565            if let StreamElement::Stream(inner) = &mut held.element {
1566                let kept: Vec<(StreamEvent, Option<usize>)> = inner
1567                    .events()
1568                    .iter()
1569                    .enumerate()
1570                    .filter(|(_, event)| {
1571                        !matches!(
1572                            event.element(),
1573                            StreamElement::Clef(_) | StreamElement::TimeSignature(_)
1574                        )
1575                    })
1576                    .map(|(index, event)| (event.clone(), Some(index)))
1577                    .collect();
1578                inner.replace_events(kept);
1579            }
1580            let copy = held.element.clone();
1581            target_length = copy.quarter_length();
1582            site.variant_mut(id)?.contents.push(copy);
1583        } else {
1584            let target = previous_element(&site, id)?.ok_or_else(|| {
1585                variant_error("'NoneType' object has no attribute 'getOffsetBySite'")
1586            })?;
1587            let held = site
1588                .get(target)
1589                .ok_or_else(|| variant_error("the element is not in the stream"))?
1590                .clone();
1591            target_length = held.element.quarter_length();
1592            let variant = site.variant_mut(id)?;
1593            shift_contents(&mut variant.contents, target_length);
1594            put(&mut variant.contents, 0.0, held.element.clone());
1595            let moving = site
1596                .remove(id)
1597                .ok_or_else(|| variant_error("Variant not found in stream"))?;
1598            site.reinsert(moving, held.offset);
1599        }
1600        let variant = site.variant_mut(id)?;
1601        let old = variant.replacement_quarter_length();
1602        variant.replacement_quarter_length = Some(op_frac(old + target_length));
1603    }
1604    let (out, moved) = site.finish(stream.clone());
1605    *stream = out;
1606    Ok(moved)
1607}
1608
1609/// music21's `_getNextElements`: the first measure, note or rest of the
1610/// kind the variant holds (or, for a deletion, replaces) at or after where
1611/// it starts (or ends).
1612fn next_element(site: &Site, id: usize) -> Result<Option<usize>> {
1613    let found = replaced(site, id, &[], false, false)?;
1614    let variant = site.variant(id)?;
1615    let offset = site.offset(id)?;
1616    let (class, start) = if variant.length_type() == LengthType::Elongation {
1617        (
1618            first_of_kinds(variant.contents.events().iter().map(StreamEvent::element)),
1619            offset,
1620        )
1621    } else {
1622        (
1623            first_of_kinds(
1624                found
1625                    .iter()
1626                    .filter_map(|(found_id, _)| site.get(*found_id).map(|held| &held.element)),
1627            ),
1628            offset + variant.replacement_quarter_length(),
1629        )
1630    };
1631    let Some(class) = class else {
1632        return Ok(None);
1633    };
1634    Ok(site
1635        .in_span(start, Some(site.highest_time()), true)
1636        .into_iter()
1637        .find(|candidate| {
1638            site.get(*candidate)
1639                .is_some_and(|held| is_a(&held.element, class))
1640        }))
1641}
1642
1643/// music21's `_getPreviousElement`: the last measure, note or rest of the
1644/// kind the variant holds (or replaces) before it.
1645fn previous_element(site: &Site, id: usize) -> Result<Option<usize>> {
1646    let found = replaced(site, id, &[], false, false)?;
1647    let variant = site.variant(id)?;
1648    let class = if variant.length_type() == LengthType::Elongation {
1649        first_of_kinds(variant.contents.events().iter().map(StreamEvent::element))
1650    } else {
1651        first_of_kinds(
1652            found
1653                .iter()
1654                .filter_map(|(found_id, _)| site.get(*found_id).map(|held| &held.element)),
1655        )
1656    };
1657    let class = class
1658        .ok_or_else(|| variant_error("Cannot find any Measures, Notes, or Rests in variant"))?;
1659    let offset = site.offset(id)?;
1660    Ok(site
1661        .in_span(0.0, Some(offset), false)
1662        .into_iter()
1663        .rfind(|candidate| {
1664            site.get(*candidate)
1665                .is_some_and(|held| is_a(&held.element, class))
1666        }))
1667}
1668
1669/// Moves each variant starting inside another's span to start where that
1670/// one does, a hidden rest put before what it holds, as music21's
1671/// `makeVariantBlocks` does.
1672///
1673/// music21 fails as soon as it has moved one, so this does too, the one
1674/// moved.
1675///
1676/// # Errors
1677///
1678/// A variant starting inside another's span, once it is moved.
1679pub fn make_variant_blocks(stream: &mut Stream) -> Result<()> {
1680    let mut site = Site::of(stream);
1681    let mut failed = None;
1682    'variants: for id in site.variants() {
1683        let start = site.offset(id)?;
1684        let end = site.variant(id)?.replacement_quarter_length() + start;
1685        let conflicting: Vec<usize> = site
1686            .in_span(start, Some(end), false)
1687            .into_iter()
1688            .filter(|other| {
1689                matches!(
1690                    site.get(*other).map(|held| &held.element),
1691                    Some(StreamElement::Variant(_))
1692                )
1693            })
1694            .collect();
1695        for other in conflicting {
1696            let other_start = site.offset(other)?;
1697            if other_start == start {
1698                continue;
1699            }
1700            let shift = op_frac(other_start - start);
1701            let variant = site.variant_mut(other)?;
1702            let old = variant.replacement_quarter_length();
1703            shift_contents(&mut variant.contents, shift);
1704            let mut rest = Rest::new(Duration::new(shift)?);
1705            rest.set_hidden(true);
1706            put(&mut variant.contents, 0.0, StreamElement::Rest(rest));
1707            variant.replacement_quarter_length = Some(old);
1708            let moving = site
1709                .remove(other)
1710                .ok_or_else(|| variant_error("Variant not found in stream"))?;
1711            site.reinsert(moving, start);
1712            failed = Some(variant_error(
1713                "'StreamIterator' object has no attribute 'append'",
1714            ));
1715            break 'variants;
1716        }
1717    }
1718    let (out, _) = site.finish(stream.clone());
1719    *stream = out;
1720    failed.map_or(Ok(()), Err)
1721}
1722
1723// ------------------------------------------------------------ activation
1724
1725/// What one variant made real leaves to renumber measures by.
1726enum Renumber {
1727    /// A measure taken out, by its number.
1728    Deleted(IntegerType),
1729    /// Measures put in after the measure of a number, by their ids.
1730    Inserted(Option<IntegerType>, Vec<usize>),
1731}
1732
1733impl Renumber {
1734    fn key(&self) -> IntegerType {
1735        match self {
1736            Self::Deleted(number) => *number,
1737            Self::Inserted(prior, _) => prior.unwrap_or(-9999),
1738        }
1739    }
1740}
1741
1742/// The variant `id` made real, everything it replaces put in a variant of
1743/// group `default` in its place: music21's `_insertReplacementVariant`.
1744fn activate_replacement(site: &mut Site, id: usize, match_by_span: bool) -> Result<()> {
1745    let variant = site.variant(id)?.clone();
1746    let start = site.offset(id)?;
1747    let mut removed = Variant::named("default");
1748    if !match_by_span {
1749        let mut matched = 0;
1750        for event in variant.contents.events() {
1751            // Where music21 looks: the variant's offset and the element's
1752            // added as Python adds them.
1753            let exact = Exact::held(start).plus(Exact::held(event.offset()));
1754            let at = exact.to_float();
1755            let class = event.element().music21_classes()[0];
1756            let target = site.held.iter().find(|held| {
1757                is_a(&held.element, class)
1758                    && at_offset(held.offset, length_of(&held.element), exact)
1759            });
1760            let target = target.map(|held| held.id);
1761            if let Some(target) = target {
1762                matched += 1;
1763                let taken = site
1764                    .remove(target)
1765                    .ok_or_else(|| variant_error("the element is not in the stream"))?;
1766                let mut element = event.element().clone();
1767                if let Some(number) = measure_number(&taken.element) {
1768                    set_measure_number(&mut element, number);
1769                }
1770                removed.contents.push(taken.element);
1771                site.insert(at, element);
1772            }
1773        }
1774        if matched > 0 {
1775            site.remove(id);
1776            site.insert(start, removed.into());
1777        }
1778        return Ok(());
1779    }
1780    let mut deleted = VecDeque::new();
1781    for (target, _) in replaced(site, id, &[], false, false)? {
1782        let at = op_frac(site.offset(target)? - start);
1783        let taken = site
1784            .remove(target)
1785            .ok_or_else(|| variant_error("the element is not in the stream"))?;
1786        if let Some(number) = measure_number(&taken.element) {
1787            deleted.push_back(number);
1788        }
1789        put(&mut removed.contents, at, taken.element);
1790    }
1791    for event in variant.contents.events() {
1792        let mut element = event.element().clone();
1793        if is_measure(&element) {
1794            set_measure_number(&mut element, deleted.pop_front().unwrap_or(0));
1795        }
1796        site.insert(start + event.offset(), element);
1797    }
1798    site.remove(id);
1799    site.insert(start, removed.into());
1800    Ok(())
1801}
1802
1803/// The variant `id`, shorter or longer than what it replaces, made real:
1804/// music21's `_insertDeletionVariant` and `_insertInsertionVariant`. The
1805/// answer is the measures taken out that nothing took the number of, and
1806/// the measures put in that took none, after the highest number before
1807/// them.
1808fn activate_changed_length(
1809    site: &mut Site,
1810    id: usize,
1811    insertion: bool,
1812) -> Result<(Vec<IntegerType>, Renumber)> {
1813    let variant = site.variant(id)?.clone();
1814    let start = site.offset(id)?;
1815    let mut removed = Variant::named("default");
1816    removed.replacement_quarter_length = Some(variant.contained_highest_time());
1817    let mut deleted = VecDeque::new();
1818    for (target, _) in replaced(site, id, &[], false, false)? {
1819        let at = op_frac(site.offset(target)? - start);
1820        let taken = site
1821            .remove(target)
1822            .ok_or_else(|| variant_error("the element is not in the stream"))?;
1823        if let Some(number) = measure_number(&taken.element) {
1824            deleted.push_back(number);
1825        }
1826        put(&mut removed.contents, at, taken.element);
1827    }
1828    let mut highest = None;
1829    let mut inserted = Vec::new();
1830    for event in variant.contents.events() {
1831        let mut element = event.element().clone();
1832        let mut new_measure = false;
1833        if is_measure(&element) {
1834            match deleted.pop_front() {
1835                Some(number) => {
1836                    set_measure_number(&mut element, number);
1837                    highest = Some(number);
1838                }
1839                None => {
1840                    set_measure_number(&mut element, 0);
1841                    new_measure = true;
1842                }
1843            }
1844        }
1845        let new_id = site.insert(start + event.offset(), element);
1846        if new_measure {
1847            inserted.push(new_id);
1848        }
1849    }
1850    if insertion && highest.is_none() {
1851        let mut most = 0;
1852        for measure in site.in_span(0.0, Some(site.offset(id)?), true) {
1853            if let Some(number) = site
1854                .get(measure)
1855                .and_then(|held| measure_number(&held.element))
1856                && number > most
1857            {
1858                most = number;
1859            }
1860        }
1861        highest = Some(most);
1862    }
1863    site.remove(id);
1864    site.insert(start, removed.into());
1865    Ok((
1866        deleted.into_iter().collect(),
1867        Renumber::Inserted(highest, inserted),
1868    ))
1869}
1870
1871/// How far to move what stands from one offset to the next opening, and
1872/// what to move only as far as the openings before.
1873struct Opening<'a> {
1874    shift: FloatType,
1875    end: FloatType,
1876    include_end: bool,
1877    exempt: &'a Vec<usize>,
1878    exempt_shift: FloatType,
1879}
1880
1881/// Moves elements back over gaps (`remove`) or on to open them, as
1882/// music21's `_removeOrExpandGaps` does: each gap a start, a length and
1883/// elements left where they are.
1884fn shift_gaps(site: &mut Site, gaps: &[(FloatType, FloatType, Vec<usize>)], remove: bool) {
1885    let duration = site.highest_time();
1886    let mut sorted: Vec<&(FloatType, FloatType, Vec<usize>)> = gaps.iter().collect();
1887    sorted.sort_by(|left, right| left.0.total_cmp(&right.0));
1888    let bounds = |i: usize| -> (FloatType, bool) {
1889        match sorted.get(i + 1) {
1890            Some(next) => (next.0, false),
1891            None => (duration, true),
1892        }
1893    };
1894    if remove {
1895        let mut shift = 0.0;
1896        for (i, (start, amount, exempt)) in sorted.iter().enumerate() {
1897            let (end, include_end) = bounds(i);
1898            shift += amount;
1899            for id in site.in_span(start + amount, Some(end), include_end) {
1900                if exempt.contains(&id) {
1901                    continue;
1902                }
1903                if let Some(held) = site.get_mut(id) {
1904                    held.offset = op_frac(held.offset - shift);
1905                }
1906            }
1907        }
1908    } else {
1909        let mut shift = 0.0;
1910        // music21 keys them by start, a later one replacing an earlier.
1911        let mut shifts: Vec<(FloatType, Opening<'_>)> = Vec::new();
1912        for (i, (start, amount, exempt)) in sorted.iter().enumerate() {
1913            let (end, include_end) = bounds(i);
1914            let exempt_shift = shift;
1915            shift += amount;
1916            let entry = Opening {
1917                shift,
1918                end,
1919                include_end,
1920                exempt,
1921                exempt_shift,
1922            };
1923            match shifts.iter_mut().find(|(known, _)| known == start) {
1924                Some((_, held)) => *held = entry,
1925                None => shifts.push((*start, entry)),
1926            }
1927        }
1928        shifts.sort_by(|left, right| right.0.total_cmp(&left.0));
1929        for (offset, opening) in shifts {
1930            for id in site.in_span(offset, Some(opening.end), opening.include_end) {
1931                let by = if opening.exempt.contains(&id) {
1932                    opening.exempt_shift
1933                } else {
1934                    opening.shift
1935                };
1936                if let Some(held) = site.get_mut(id) {
1937                    held.offset = op_frac(held.offset + by);
1938                }
1939            }
1940        }
1941    }
1942    site.sort();
1943}
1944
1945/// music21's `_fixMeasureNumbers`.
1946fn fix_measure_numbers(site: &mut Site, mut all: Vec<Renumber>) -> Result<()> {
1947    if all.is_empty() {
1948        return Ok(());
1949    }
1950    all.sort_by_key(Renumber::key);
1951    let mut old_measures = site.measures();
1952    let mut new_measures: Vec<usize> = Vec::new();
1953    let mut cumulative: IntegerType = 0;
1954    let mut old_corrections: Vec<(IntegerType, IntegerType)> = Vec::new();
1955    let mut new_corrections: Vec<(IntegerType, IntegerType)> = Vec::new();
1956    let correct =
1957        |corrections: &mut Vec<(IntegerType, IntegerType)>, at: IntegerType, by: IntegerType| {
1958            match corrections.iter_mut().find(|(known, _)| *known == at) {
1959                Some((_, held)) => *held = by,
1960                None => corrections.push((at, by)),
1961            }
1962        };
1963    for entry in all {
1964        match entry {
1965            Renumber::Inserted(prior, measures) => {
1966                if measures.is_empty() {
1967                    continue;
1968                }
1969                let prior = prior.ok_or_else(|| {
1970                    variant_error("unsupported operand type(s) for +: 'NoneType' and 'int'")
1971                })?;
1972                cumulative += measures.len() as IntegerType;
1973                let mut next = prior + 1;
1974                for id in measures {
1975                    // music21 takes out nothing for a measure no longer here.
1976                    old_measures.retain(|known| *known != id);
1977                    new_measures.push(id);
1978                    if let Some(held) = site.get_mut(id) {
1979                        set_measure_number(&mut held.element, next);
1980                    }
1981                    next += 1;
1982                }
1983                correct(&mut old_corrections, prior + 1, cumulative);
1984                correct(&mut new_corrections, next, cumulative);
1985            }
1986            Renumber::Deleted(number) => {
1987                cumulative -= 1;
1988                correct(&mut old_corrections, number + 1, cumulative);
1989                correct(&mut new_corrections, number + 1, cumulative);
1990            }
1991        }
1992    }
1993    for (measures, corrections) in [
1994        (old_measures, old_corrections),
1995        (new_measures, new_corrections),
1996    ] {
1997        let mut corrections = corrections;
1998        corrections.sort_by_key(|(at, _)| -*at);
1999        let mut previous: Option<IntegerType> = None;
2000        for (at, shift) in corrections {
2001            for &id in &measures {
2002                let Some(held) = site.get_mut(id) else {
2003                    continue;
2004                };
2005                let Some(number) = measure_number(&held.element) else {
2006                    continue;
2007                };
2008                if previous.is_none_or(|boundary| number < boundary) && number >= at {
2009                    set_measure_number(&mut held.element, number + shift);
2010                }
2011            }
2012            previous = Some(at);
2013        }
2014    }
2015    Ok(())
2016}
2017
2018impl Stream {
2019    /// A copy of the stream with its variants of `group` (or all of them)
2020    /// made its reading, as music21's `activateVariants` makes them: what
2021    /// each replaces goes into a variant of group `default` in its place, a
2022    /// longer or shorter one moving what follows, and the measures are
2023    /// numbered again. With `match_by_span`, a variant replaces everything
2024    /// of its classes within its span; without, each of its elements the
2025    /// first of its class where it starts.
2026    ///
2027    /// ```
2028    /// use music21_rs::tinynotation::from_tiny_notation;
2029    /// use music21_rs::variant::merge_variants;
2030    ///
2031    /// let first = from_tiny_notation("4/4 c1 d1 e1")?;
2032    /// let second = from_tiny_notation("4/4 c1 f1 e1")?;
2033    /// let merged = merge_variants(&first, &second, "second")?;
2034    /// let made = merged.activate_variants(Some("second"), true)?;
2035    /// assert_eq!(made.pitches()[1].name(), "F");
2036    /// # Ok::<(), music21_rs::Error>(())
2037    /// ```
2038    ///
2039    /// # Errors
2040    ///
2041    /// A variant that cannot say what it replaces, or measures put in after
2042    /// none to be numbered from, where music21 fails.
2043    pub fn activate_variants(&self, group: Option<&str>, match_by_span: bool) -> Result<Stream> {
2044        let mut site = Site::of(self);
2045        let (mut elongations, mut deletions) = (Vec::new(), Vec::new());
2046        for id in site.variants() {
2047            let variant = site.variant(id)?;
2048            if group.is_some_and(|group| !variant.groups.iter().any(|known| known == group)) {
2049                continue;
2050            }
2051            match variant.length_type() {
2052                LengthType::Elongation => elongations.push(id),
2053                LengthType::Deletion => deletions.push(id),
2054                LengthType::Replacement => activate_replacement(&mut site, id, match_by_span)?,
2055            }
2056        }
2057        let mut deleted: Vec<Renumber> = Vec::new();
2058        let mut inserted: Vec<Renumber> = Vec::new();
2059        let mut gaps = Vec::new();
2060        for id in deletions {
2061            let variant = site.variant(id)?;
2062            let difference =
2063                variant.replacement_quarter_length() - variant.contained_highest_time();
2064            let start = site.offset(id)? + variant.contained_highest_time();
2065            let (left, renumber) = activate_changed_length(&mut site, id, false)?;
2066            gaps.push((start, difference, Vec::new()));
2067            deleted.extend(left.into_iter().map(Renumber::Deleted));
2068            inserted.push(renumber);
2069        }
2070        shift_gaps(&mut site, &gaps, true);
2071        let mut openings = Vec::new();
2072        for &id in &elongations {
2073            let variant = site.variant(id)?;
2074            let difference =
2075                variant.replacement_quarter_length() - variant.contained_highest_time();
2076            let start = site.offset(id)? + variant.replacement_quarter_length();
2077            openings.push((start, -difference, vec![id]));
2078        }
2079        shift_gaps(&mut site, &openings, false);
2080        for id in elongations {
2081            let (left, renumber) = activate_changed_length(&mut site, id, true)?;
2082            inserted.push(renumber);
2083            deleted.extend(left.into_iter().map(Renumber::Deleted));
2084        }
2085        deleted.extend(inserted);
2086        fix_measure_numbers(&mut site, deleted)?;
2087        Ok(site.finish(self.clone()).0)
2088    }
2089
2090    /// A copy of a score with, for each of `variant_groups` whose variants
2091    /// replace something in the part at `part` among its parts, a part
2092    /// added showing only those variants: the part's notes and rests made
2093    /// hidden rests and its variants of that group made its reading, as
2094    /// music21's `showVariantAsOssialikePart` does.
2095    ///
2096    /// # Errors
2097    ///
2098    /// No part at `part`, or as [`Stream::activate_variants`].
2099    pub fn show_variant_as_ossialike_part(
2100        &self,
2101        part: usize,
2102        variant_groups: &[&str],
2103    ) -> Result<Stream> {
2104        let mut out = self.clone();
2105        let source = self
2106            .parts()
2107            .get(part)
2108            .map(|found| (*found).clone())
2109            .ok_or_else(|| variant_error("Could not find the part in the score"))?;
2110        for group in variant_groups {
2111            let mut expressed = false;
2112            // Each element kept with the order it went in: a rest put in
2113            // place of a note after everything already there.
2114            let mut held: Vec<(usize, StreamEvent, Option<usize>)> = Vec::new();
2115            let mut later = source.events().len();
2116            for (index, event) in source.events().iter().enumerate() {
2117                match event.element() {
2118                    StreamElement::Variant(variant) => {
2119                        if !variant.groups.iter().any(|known| known == group)
2120                            || matches!(
2121                                variant.length_type(),
2122                                LengthType::Elongation | LengthType::Deletion
2123                            )
2124                        {
2125                            continue;
2126                        }
2127                        expressed = true;
2128                        held.push((index, event.clone(), Some(index)));
2129                    }
2130                    element if is_general_note(element) => {
2131                        let mut rest = Rest::new(Duration::new(element.quarter_length())?);
2132                        rest.set_hidden(true);
2133                        held.push((
2134                            later,
2135                            StreamEvent::new(event.offset(), StreamElement::Rest(rest)),
2136                            None,
2137                        ));
2138                        later += 1;
2139                    }
2140                    StreamElement::Stream(measure) if measure.kind() == StreamKind::Measure => {
2141                        let length = highest_time(measure);
2142                        let mut emptied = (**measure).clone();
2143                        let kept: Vec<(StreamEvent, Option<usize>)> = emptied
2144                            .events()
2145                            .iter()
2146                            .enumerate()
2147                            .filter(|(_, inner)| !is_general_note(inner.element()))
2148                            .map(|(at, inner)| (inner.clone(), Some(at)))
2149                            .collect();
2150                        emptied.replace_events(kept);
2151                        let mut rest = Rest::new(Duration::new(length)?);
2152                        rest.set_hidden(true);
2153                        put(&mut emptied, 0.0, StreamElement::Rest(rest));
2154                        held.push((
2155                            index,
2156                            StreamEvent::new(
2157                                event.offset(),
2158                                StreamElement::Stream(Box::new(emptied)),
2159                            ),
2160                            Some(index),
2161                        ));
2162                    }
2163                    _ => held.push((index, event.clone(), Some(index))),
2164                }
2165            }
2166            held.sort_by(|left, right| {
2167                crate::makenotation::event_order(&left.1, &right.1).then(left.0.cmp(&right.0))
2168            });
2169            let mut new_part = source.clone();
2170            new_part.replace_events(
2171                held.into_iter()
2172                    .map(|(_, event, origin)| (event, origin))
2173                    .collect(),
2174            );
2175            let new_part = new_part.activate_variants(Some(group), true)?;
2176            if expressed {
2177                out.insert_sorted(vec![StreamEvent::new(
2178                    0.0,
2179                    StreamElement::Stream(Box::new(new_part)),
2180                )]);
2181            }
2182        }
2183        Ok(out)
2184    }
2185}