#[macro_export]
macro_rules! generate_notes_storage {
(
$(#[$note_ty_meta:meta])*
$note_ty_enum_vis:vis enum $note_ty_enum_name:ident,
$(#[$note_enum_meta:meta])*
$note_enum_vis:vis enum $note_enum_name:ident,
$(#[$snapshot_meta:meta])*
$snapshot_vis:vis enum $snapshot_name:ident,
$(#[$note_ref_meta:meta])*
$note_ref_vis:vis enum $note_ref_name:ident,
$(#[$note_mut_meta:meta])*
$note_mut_vis:vis enum $note_mut_name:ident,
$(#[$struct_meta:meta])*
$struct_vis:vis struct $struct_name:ident {
$(note_type $enum_variant:ident ($variant_ty:ty) => $field_vis: vis $field_name:ident: $storage_type: ty),*
$(, field $aux_vis: vis $aux_field:ident: $aux_ty:ty)*
$(, edit_hook $hook:expr)* $(,)?
}
) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
$(#[$note_ty_meta])*
$note_ty_enum_vis enum $note_ty_enum_name {
$($enum_variant,)*
}
#[derive(Debug, Clone)]
$(#[$note_enum_meta])*
$note_enum_vis enum $note_enum_name {
$($enum_variant($variant_ty),)*
}
#[derive(Clone)]
$(#[$snapshot_meta])*
$snapshot_vis enum $snapshot_name {
$($enum_variant($crate::notes::NoteSnapshot<$variant_ty>),)*
}
#[allow(dead_code)]
impl $snapshot_name {
pub fn note_type(&self) -> $note_ty_enum_name {
match self {
$(Self::$enum_variant(_) => $note_ty_enum_name::$enum_variant,)*
}
}
pub fn id(&self) -> u64 {
match self {
$(Self::$enum_variant(n) => n.id,)*
}
}
pub fn start_time(&self) -> $crate::rhythm::Time {
match self {
$(Self::$enum_variant(n) => $crate::notes::Note::start_time(n),)*
}
}
pub fn duration(&self) -> $crate::rhythm::Time {
match self {
$(Self::$enum_variant(n) => $crate::notes::Note::duration(n),)*
}
}
pub fn clock_time_interval(&self) -> $crate::notes::Interval<$crate::rhythm::ClockTime> {
match self {
$(Self::$enum_variant(n) => n.clock_time,)*
}
}
pub fn group_id(&self) -> &$crate::notes::GroupId {
match self {
$(Self::$enum_variant(n) => $crate::notes::Note::group_id(n),)*
}
}
pub fn to_owned_note(&self) -> $note_enum_name {
match self {
$(Self::$enum_variant(n) => $note_enum_name::$enum_variant(n.note.clone()),)*
}
}
pub fn into_owned_note(self) -> $note_enum_name {
match self {
$(Self::$enum_variant(n) => $note_enum_name::$enum_variant(n.note),)*
}
}
}
impl $crate::notes::Note for $snapshot_name {
fn start_time(&self) -> $crate::rhythm::Time {
self.start_time()
}
fn duration(&self) -> $crate::rhythm::Time {
self.duration()
}
fn group_id(&self) -> &$crate::notes::GroupId {
self.group_id()
}
}
impl $crate::notes::NoteState for $snapshot_name {
type Snapshot = Self;
fn to_snapshot(&self) -> Self {
self.clone()
}
fn id(&self) -> u64 {
self.id()
}
fn clock_time_interval(&self) -> $crate::notes::Interval<$crate::rhythm::ClockTime> {
self.clock_time_interval()
}
}
impl From<&$snapshot_name> for $note_ty_enum_name {
fn from(note: &$snapshot_name) -> Self {
note.note_type()
}
}
impl From<&$snapshot_name> for $note_enum_name {
fn from(note: &$snapshot_name) -> Self {
note.to_owned_note()
}
}
impl From<$snapshot_name> for $note_enum_name {
fn from(note: $snapshot_name) -> Self {
note.into_owned_note()
}
}
impl From<&$note_enum_name> for $note_ty_enum_name {
fn from(val: &$note_enum_name) -> Self {
val.note_type()
}
}
impl From<$note_enum_name> for $note_ty_enum_name {
fn from(val: $note_enum_name) -> Self {
val.note_type()
}
}
#[allow(dead_code)]
impl $note_enum_name {
pub fn note_type(&self) -> $note_ty_enum_name {
match self {
$(Self::$enum_variant(_) => $note_ty_enum_name::$enum_variant,)*
}
}
pub fn start_time(&self) -> $crate::rhythm::Time {
match self {
$(Self::$enum_variant(n) => $crate::notes::LongNoteData::start_time(n),)*
}
}
pub fn duration(&self) -> $crate::rhythm::Time {
match self {
$(Self::$enum_variant(n) => $crate::notes::LongNoteData::duration(n),)*
}
}
pub fn group_id(&self) -> &$crate::notes::GroupId {
match self {
$(Self::$enum_variant(n) => $crate::notes::LongNoteData::group_id(n),)*
}
}
}
$(#[$note_ref_meta])*
#[allow(unused)]
$note_ref_vis enum $note_ref_name<'a> {
$($enum_variant($crate::notes::NoteRef<'a, $variant_ty>),)*
}
#[allow(dead_code)]
impl $note_ref_name<'_> {
pub fn id(&self) -> u64 {
match self {
$(Self::$enum_variant(n) => n.id,)*
}
}
pub fn start_time(&self) -> $crate::rhythm::Time {
match self {
$(Self::$enum_variant(n) => n.start_time,)*
}
}
pub fn duration(&self) -> $crate::rhythm::Time {
match self {
$(Self::$enum_variant(n) => n.duration,)*
}
}
pub fn clock_time_interval(&self) -> $crate::notes::Interval<$crate::rhythm::ClockTime> {
match self {
$(Self::$enum_variant(n) => n.clock_time,)*
}
}
pub fn group_id(&self) -> &$crate::notes::GroupId {
match self {
$(Self::$enum_variant(n) => &n.group_id,)*
}
}
pub fn to_snapshot(&self) -> $snapshot_name {
match self {
$(Self::$enum_variant(n) => $snapshot_name::$enum_variant(n.to_snapshot()),)*
}
}
pub fn to_owned_note(&self) -> $note_enum_name {
match self {
$(Self::$enum_variant(n) => $note_enum_name::$enum_variant(
<$variant_ty as $crate::notes::LongNoteData>::reconstruct(
n.start_time, n.duration, n.value_data, n.group_id.clone(),
),
),)*
}
}
}
$(#[$note_mut_meta])*
#[allow(unused)]
$note_mut_vis enum $note_mut_name<'a> {
$($enum_variant($crate::notes::NoteMut<'a, $variant_ty>),)*
}
#[allow(dead_code)]
impl $note_mut_name<'_> {
pub fn as_ref(&self) -> $note_ref_name<'_> {
match self {
$(Self::$enum_variant(n) => $note_ref_name::$enum_variant(n.as_ref()),)*
}
}
pub fn id(&self) -> u64 {
match self {
$(Self::$enum_variant(n) => n.id,)*
}
}
pub fn start_time(&self) -> $crate::rhythm::Time {
match self {
$(Self::$enum_variant(n) => n.start_time,)*
}
}
pub fn duration(&self) -> $crate::rhythm::Time {
match self {
$(Self::$enum_variant(n) => n.duration,)*
}
}
pub fn clock_time_interval(&self) -> $crate::notes::Interval<$crate::rhythm::ClockTime> {
match self {
$(Self::$enum_variant(n) => n.clock_time,)*
}
}
pub fn group_id(&self) -> &$crate::notes::GroupId {
match self {
$(Self::$enum_variant(n) => &n.group_id,)*
}
}
pub fn to_snapshot(&self) -> $snapshot_name {
match self {
$(Self::$enum_variant(n) => $snapshot_name::$enum_variant(n.to_snapshot()),)*
}
}
pub fn to_owned_note(&self) -> $note_enum_name {
match self {
$(Self::$enum_variant(n) => $note_enum_name::$enum_variant(
<$variant_ty as $crate::notes::LongNoteData>::reconstruct(
n.start_time, n.duration, n.value_data, n.group_id.clone(),
),
),)*
}
}
}
impl<'a, 'b> From<&'a $note_mut_name<'b>> for $note_ref_name<'a> {
fn from(note: &'a $note_mut_name<'b>) -> Self {
note.as_ref()
}
}
impl From<&$note_ref_name<'_>> for $note_enum_name {
fn from(note: &$note_ref_name<'_>) -> Self {
note.to_owned_note()
}
}
impl From<&$note_mut_name<'_>> for $note_enum_name {
fn from(note: &$note_mut_name<'_>) -> Self {
note.to_owned_note()
}
}
impl From<$note_ref_name<'_>> for $note_enum_name {
fn from(note: $note_ref_name<'_>) -> Self {
note.to_owned_note()
}
}
impl From<$note_mut_name<'_>> for $note_enum_name {
fn from(note: $note_mut_name<'_>) -> Self {
note.to_owned_note()
}
}
impl $crate::notes::Note for $note_enum_name {
fn start_time(&self) -> $crate::rhythm::Time {
$note_enum_name::start_time(self)
}
fn duration(&self) -> $crate::rhythm::Time {
$note_enum_name::duration(self)
}
fn group_id(&self) -> &$crate::notes::GroupId {
$note_enum_name::group_id(self)
}
}
impl $crate::notes::Note for $note_ref_name<'_> {
fn start_time(&self) -> $crate::rhythm::Time {
$note_ref_name::start_time(self)
}
fn duration(&self) -> $crate::rhythm::Time {
$note_ref_name::duration(self)
}
fn group_id(&self) -> &$crate::notes::GroupId {
$note_ref_name::group_id(self)
}
}
impl $crate::notes::NoteState for $note_ref_name<'_> {
type Snapshot = $snapshot_name;
fn to_snapshot(&self) -> Self::Snapshot {
$note_ref_name::to_snapshot(self)
}
fn id(&self) -> u64 {
$note_ref_name::id(self)
}
fn clock_time_interval(&self) -> $crate::notes::Interval<$crate::rhythm::ClockTime> {
$note_ref_name::clock_time_interval(self)
}
}
impl $crate::notes::Note for $note_mut_name<'_> {
fn start_time(&self) -> $crate::rhythm::Time {
$note_mut_name::start_time(self)
}
fn duration(&self) -> $crate::rhythm::Time {
$note_mut_name::duration(self)
}
fn group_id(&self) -> &$crate::notes::GroupId {
$note_mut_name::group_id(self)
}
}
impl $crate::notes::NoteState for $note_mut_name<'_> {
type Snapshot = $snapshot_name;
fn to_snapshot(&self) -> Self::Snapshot {
$note_mut_name::to_snapshot(self)
}
fn id(&self) -> u64 {
$note_mut_name::id(self)
}
fn clock_time_interval(&self) -> $crate::notes::Interval<$crate::rhythm::ClockTime> {
$note_mut_name::clock_time_interval(self)
}
}
$(#[$struct_meta])*
$struct_vis struct $struct_name {
$($field_vis $field_name: $storage_type,)*
$($aux_vis $aux_field: $aux_ty,)*
}
#[allow(dead_code)]
impl $struct_name {
$(
#[doc = concat!("Shared reference to the `", stringify!($field_name), "` note storage.")]
#[inline]
pub fn $field_name(&self) -> &$storage_type {
&self.$field_name
}
)*
pub fn new() -> Self {
Self {
$($field_name: Default::default(),)*
$($aux_field: Default::default(),)*
}
}
pub fn with_notes<G: $crate::notes::NoteGroup>(
notes: Vec<$note_enum_name>,
note_groups: &mut $crate::notes::NoteGroups<G>,
tempo_tracks: &mut $crate::rhythm::TempoTracks,
scroll_tracks: &mut $crate::rhythm::ScrollSpeedTracks,
) -> Self {
let mut s = Self::new();
$crate::notes::NotesStorage::add_notes(
&mut s, note_groups, tempo_tracks, scroll_tracks, notes
);
s
}
}
impl $crate::notes::NotesStorage for $struct_name {
type NoteTypeEnum = $note_ty_enum_name;
type NoteEnum = $note_enum_name;
type NoteSnapshotEnum = $snapshot_name;
type NoteRefEnum<'a> = $note_ref_name<'a>;
type NoteMutEnum<'a> = $note_mut_name<'a>;
fn rebuild_clock_time<G: $crate::notes::NoteGroup>(
&mut self,
note_groups: &$crate::notes::NoteGroups<G>,
tempo_tracks: &$crate::rhythm::TempoTracks,
scroll_tracks: &$crate::rhythm::ScrollSpeedTracks,
) {
$(self.$field_name.rebuild_clock_time(
note_groups,
tempo_tracks,
scroll_tracks);)*
let mut hooks = $crate::generate_notes_storage!(@edit_hooks_tuple $($hook),*);
$crate::notes::NotesStorageEditHook::post_rebuild_clock_time(&mut hooks, self);
}
fn rebuild_scroll_pos<G: $crate::notes::NoteGroup>(
&mut self,
note_groups: &$crate::notes::NoteGroups<G>,
tempo_tracks: &$crate::rhythm::TempoTracks,
scroll_tracks: &$crate::rhythm::ScrollSpeedTracks,
) {
$(self.$field_name.rebuild_scroll_pos(
note_groups,
tempo_tracks,
scroll_tracks);)*
let mut hooks = $crate::generate_notes_storage!(@edit_hooks_tuple $($hook),*);
$crate::notes::NotesStorageEditHook::post_rebuild_scroll_pos(&mut hooks, self);
}
fn add_note<G: $crate::notes::NoteGroup>(
&mut self,
note_groups: &mut $crate::notes::NoteGroups<G>,
tempo_tracks: &mut $crate::rhythm::TempoTracks,
scroll_tracks: &mut $crate::rhythm::ScrollSpeedTracks,
mut note: $note_enum_name,
) {
let mut hooks = $crate::generate_notes_storage!(@edit_hooks_tuple $($hook),*);
$crate::notes::NotesStorageEditHook::pre_add(&mut hooks, self, ::std::slice::from_mut(&mut note));
match note {
$($note_enum_name::$enum_variant(n) => {
let note_id = self.$field_name.add_note(
note_groups,
tempo_tracks,
scroll_tracks,
n);
$crate::notes::NotesStorageEditHook::post_add(
&mut hooks,
self,
&[(note_id, $note_ty_enum_name::$enum_variant)],
);
})*
}
}
fn add_notes<G: $crate::notes::NoteGroup>(&mut self,
note_groups: &mut $crate::notes::NoteGroups<G>,
tempo_tracks: &mut $crate::rhythm::TempoTracks,
scroll_tracks: &mut $crate::rhythm::ScrollSpeedTracks,
mut notes: ::std::vec::Vec<$note_enum_name>,
) {
let mut hooks = $crate::generate_notes_storage!(@edit_hooks_tuple $($hook),*);
if !notes.is_empty() {
$crate::notes::NotesStorageEditHook::pre_add(&mut hooks, self, &mut notes);
}
let mut added = ::std::vec::Vec::with_capacity(notes.len());
$(let mut $field_name: ::std::vec::Vec<$variant_ty> = ::std::vec::Vec::new();)*
for note in notes {
match note {
$($note_enum_name::$enum_variant(n) => $field_name.push(n),)*
}
}
$(
if !$field_name.is_empty() {
let note_ids = self.$field_name.add_notes(
&mut *note_groups,
&mut *tempo_tracks,
&mut *scroll_tracks,
$field_name.into_iter());
added.extend(note_ids.into_iter().map(|id| (id, $note_ty_enum_name::$enum_variant)));
}
)*
if !added.is_empty() {
$crate::notes::NotesStorageEditHook::post_add(&mut hooks, self, &added);
}
}
fn remove_note(&mut self, note_type: $note_ty_enum_name, id: u64) {
let mut hooks = $crate::generate_notes_storage!(@edit_hooks_tuple $($hook),*);
match note_type {
$($note_ty_enum_name::$enum_variant => {
let queried = self.$field_name.query_notes_ref(::std::iter::once(id))
.map(|state| $note_ref_name::$enum_variant(state).to_snapshot()).next();
let Some(note) = queried else {
return;
};
let note_id = note.id();
$crate::notes::NotesStorageEditHook::pre_remove(
&mut hooks,
self,
::std::slice::from_ref(¬e),
);
self.$field_name.remove_note(note_id);
$crate::notes::NotesStorageEditHook::post_remove(&mut hooks, self, ::std::slice::from_ref(¬e));
})*
}
}
fn remove_notes(&mut self,
mut notes: ::std::vec::Vec<(u64, $note_ty_enum_name)>,
) {
let mut hooks = $crate::generate_notes_storage!(@edit_hooks_tuple $($hook),*);
notes.sort_unstable_by_key(|(id, ty)| (*ty as usize, *id));
notes.dedup();
let queried: ::std::vec::Vec<_> = self.query_notes(notes.iter().copied()).collect();
if !queried.is_empty() {
$crate::notes::NotesStorageEditHook::pre_remove(&mut hooks, self, &queried);
}
$(
self.$field_name.remove_notes(queried.iter().filter_map(|note| {
(note.note_type() == $note_ty_enum_name::$enum_variant).then_some(note.id())
}));
)*
if !queried.is_empty() {
$crate::notes::NotesStorageEditHook::post_remove(&mut hooks, self, &queried);
}
}
fn query_notes(&self,
ids: impl Iterator<Item = (u64, $note_ty_enum_name)> + Clone
) -> impl Iterator<Item = $snapshot_name> {
::std::iter::empty()
$(.chain(self.$field_name.query_notes_ref(
#[allow(unreachable_patterns)]
ids.clone().filter_map(|(id, ty)| match ty {
$note_ty_enum_name::$enum_variant => Some(id),
_ => None,
})
).map(|state| $note_ref_name::$enum_variant(state).to_snapshot())))*
}
fn all_notes(&self) -> impl Iterator<Item = $snapshot_name> {
::std::iter::empty()
$(.chain(self.$field_name.all_notes_ref()
.map(|state| $note_ref_name::$enum_variant(state).to_snapshot())))*
}
fn all_notes_of_type(&self,
note_type: $note_ty_enum_name,
) -> impl Iterator<Item = $snapshot_name> {
self.all_notes_ref_of_type(note_type).map(|state| state.to_snapshot())
}
fn all_notes_ref_of_type<'a>(&'a self,
note_type: $note_ty_enum_name,
) -> impl Iterator<Item = $note_ref_name<'a>> + 'a
where
Self: 'a,
{
::std::iter::empty()
$(.chain(
::std::iter::once(&self.$field_name)
.filter(move |_| matches!(note_type, $note_ty_enum_name::$enum_variant))
.flat_map(|storage| storage.all_notes_ref())
.map($note_ref_name::$enum_variant)
))*
}
fn all_notes_mut_of_type(&mut self,
note_type: $note_ty_enum_name,
mut f: impl FnMut($note_mut_name<'_>),
) {
match note_type {
$($note_ty_enum_name::$enum_variant => {
self.$field_name.all_notes_mut(
|state| f($note_mut_name::$enum_variant(state)),
);
})*
}
}
fn query_notes_ref<'a>(&'a self,
ids: impl Iterator<Item = (u64, $note_ty_enum_name)> + Clone + 'a
) -> impl Iterator<Item = $note_ref_name<'a>> + 'a
where
Self: 'a
{
::std::iter::empty()
$(
.chain(
self.$field_name.query_notes_ref(
#[allow(unreachable_patterns)]
ids.clone().filter_map(|(id, note_type)| match note_type {
$note_ty_enum_name::$enum_variant => Some(id),
_ => None,
})
).map(|state| $note_ref_name::$enum_variant(state))
)
)*
}
fn query_notes_mut(&mut self,
ids: impl Iterator<Item = (u64, $note_ty_enum_name)> + Clone,
mut f: impl FnMut($note_mut_name<'_>),
) {
$(
self.$field_name.query_notes_mut(
#[allow(unreachable_patterns)]
ids.clone().filter_map(|(id, note_type)| match note_type {
$note_ty_enum_name::$enum_variant => Some(id),
_ => None,
}),
|state| f($note_mut_name::$enum_variant(state)),
);
)*
}
fn notes_overlapping_range(&self,
range: $crate::notes::Interval<$crate::rhythm::ClockTime>
) -> impl Iterator<Item = $snapshot_name> {
self.notes_ref_overlapping_range(range).map(|state| state.to_snapshot())
}
fn notes_ref_overlapping_range<'a>(&'a self,
range: $crate::notes::Interval<$crate::rhythm::ClockTime>
) -> impl Iterator<Item = $note_ref_name<'a>> + 'a
where
Self: 'a
{
::std::iter::empty()
$(
.chain(
self.$field_name.notes_ref_overlapping_range(range)
.map(|state| $note_ref_name::$enum_variant(state))
)
)*
}
fn notes_mut_overlapping_range(&mut self,
range: $crate::notes::Interval<$crate::rhythm::ClockTime>,
mut f: impl FnMut($note_mut_name<'_>),
) {
$(
self.$field_name.notes_mut_overlapping_range(
range,
|state| f($note_mut_name::$enum_variant(state)),
);
)*
}
fn extract_notes(&mut self,
mut notes: ::std::vec::Vec<(u64, $note_ty_enum_name)>,
mut f: impl FnMut($snapshot_name),
) {
let mut hooks = $crate::generate_notes_storage!(@edit_hooks_tuple $($hook),*);
notes.sort_unstable_by_key(|(id, ty)| (*ty as usize, *id));
notes.dedup();
let queried: ::std::vec::Vec<_> = self.query_notes(notes.iter().copied()).collect();
if !queried.is_empty() {
$crate::notes::NotesStorageEditHook::pre_remove(&mut hooks, self, &queried);
}
$(
self.$field_name.remove_notes(queried.iter().filter_map(|note| {
(note.note_type() == $note_ty_enum_name::$enum_variant).then_some(note.id())
}));
)*
for note in &queried { f(note.clone()); }
if !queried.is_empty() {
$crate::notes::NotesStorageEditHook::post_remove(&mut hooks, self, &queried);
}
}
fn replace_note<G: $crate::notes::NoteGroup>(&mut self,
note_groups: &mut $crate::notes::NoteGroups<G>,
tempo_tracks: &mut $crate::rhythm::TempoTracks,
scroll_tracks: &mut $crate::rhythm::ScrollSpeedTracks,
id: u64,
note: $note_enum_name,
) {
let mut hooks = $crate::generate_notes_storage!(@edit_hooks_tuple $($hook),*);
let note_type = note.note_type();
let queried = self
.query_notes(::std::iter::once((id, note_type)))
.next();
let Some(before) = queried else {
return;
};
let note_id = before.id();
let mut replacement = (note_id, note);
$crate::notes::NotesStorageEditHook::pre_update(
&mut hooks, self, ::std::slice::from_mut(&mut replacement),
);
match replacement.1 {
$($note_enum_name::$enum_variant(n) => {
self.$field_name.replace_note(
note_groups,
tempo_tracks,
scroll_tracks,
note_id,
n);
})*
}
let after = self
.query_notes(::std::iter::once((note_id, before.note_type())))
.next();
if let Some(after) = after {
$crate::notes::NotesStorageEditHook::post_update(
&mut hooks,
self,
&[(before, after)],
);
}
}
fn replace_notes<G: $crate::notes::NoteGroup>(&mut self,
note_groups: &mut $crate::notes::NoteGroups<G>,
tempo_tracks: &mut $crate::rhythm::TempoTracks,
scroll_tracks: &mut $crate::rhythm::ScrollSpeedTracks,
mut notes: ::std::vec::Vec<(u64, $note_enum_name)>,
) {
let mut hooks = $crate::generate_notes_storage!(@edit_hooks_tuple $($hook),*);
notes.reverse();
notes.sort_by_key(|(id, note)| (note.note_type() as usize, *id));
notes.dedup_by_key(|(id, note)| (note.note_type() as usize, *id));
let mut befores: ::std::vec::Vec<_> = self
.query_notes(notes.iter().map(|(id, note)| (*id, note.note_type())))
.collect();
befores.sort_unstable_by_key(|note| (note.note_type() as usize, note.id()));
notes.retain(|(id, note)| befores.binary_search_by_key(
&(note.note_type() as usize, *id),
|before| (before.note_type() as usize, before.id()),
).is_ok());
if !notes.is_empty() {
$crate::notes::NotesStorageEditHook::pre_update(&mut hooks, self, &mut notes);
}
$(let mut $field_name: ::std::vec::Vec<(u64, $variant_ty)> =
::std::vec::Vec::new();)*
for (id, note) in notes {
match note {
$($note_enum_name::$enum_variant(n) => $field_name.push((id, n)),)*
}
}
$(
if !$field_name.is_empty() {
self.$field_name.replace_notes(
&mut *note_groups,
&mut *tempo_tracks,
&mut *scroll_tracks,
$field_name.into_iter());
}
)*
let updates: ::std::vec::Vec<_> = befores.into_iter().filter_map(|before| {
self.query_notes(::std::iter::once((before.id(), before.note_type())))
.next().map(|after| (before, after))
}).collect();
if !updates.is_empty() {
$crate::notes::NotesStorageEditHook::post_update(&mut hooks, self, &updates);
}
}
}
impl Default for $struct_name {
fn default() -> Self {
Self::new()
}
}
};
(@edit_hooks_tuple) => { () };
(@edit_hooks_tuple $hook:expr) => { $hook };
(@edit_hooks_tuple $first:expr, $($rest:expr),+) => {
($first, $crate::generate_notes_storage!(@edit_hooks_tuple $($rest),+))
};
}
pub trait Note {
fn start_time(&self) -> crate::rhythm::Time;
fn duration(&self) -> crate::rhythm::Time;
fn group_id(&self) -> &crate::notes::GroupId;
}
pub trait NoteState: Note {
type Snapshot: NoteState<Snapshot = Self::Snapshot> + Clone;
fn to_snapshot(&self) -> Self::Snapshot;
fn id(&self) -> u64;
fn clock_time_interval(&self) -> crate::notes::Interval<crate::rhythm::ClockTime>;
}
pub trait NotesStorage {
type NoteTypeEnum: Clone
+ Copy
+ Eq
+ for<'a> From<&'a Self::NoteEnum>
+ for<'a> From<&'a Self::NoteSnapshotEnum>
+ 'static;
type NoteEnum: Note
+ Clone
+ for<'a> From<&'a Self::NoteSnapshotEnum>
+ for<'a, 'b> From<&'a Self::NoteRefEnum<'b>>
+ for<'a, 'b> From<&'a Self::NoteMutEnum<'b>>;
type NoteSnapshotEnum: NoteState<Snapshot = Self::NoteSnapshotEnum> + Clone;
type NoteRefEnum<'a>: NoteState<Snapshot = Self::NoteSnapshotEnum>
+ for<'b> From<&'a Self::NoteMutEnum<'b>>
where
Self: 'a;
type NoteMutEnum<'a>: NoteState<Snapshot = Self::NoteSnapshotEnum>
where
Self: 'a;
fn rebuild_clock_time<G: crate::notes::NoteGroup>(
&mut self,
note_groups: &crate::notes::NoteGroups<G>,
tempo_tracks: &crate::rhythm::TempoTracks,
scroll_tracks: &crate::rhythm::ScrollSpeedTracks,
);
fn rebuild_scroll_pos<G: crate::notes::NoteGroup>(
&mut self,
note_groups: &crate::notes::NoteGroups<G>,
tempo_tracks: &crate::rhythm::TempoTracks,
scroll_tracks: &crate::rhythm::ScrollSpeedTracks,
);
fn add_note<G: crate::notes::NoteGroup>(
&mut self,
note_groups: &mut crate::notes::NoteGroups<G>,
tempo_tracks: &mut crate::rhythm::TempoTracks,
scroll_tracks: &mut crate::rhythm::ScrollSpeedTracks,
note: Self::NoteEnum,
);
fn add_notes<G: crate::notes::NoteGroup>(
&mut self,
note_groups: &mut crate::notes::NoteGroups<G>,
tempo_tracks: &mut crate::rhythm::TempoTracks,
scroll_tracks: &mut crate::rhythm::ScrollSpeedTracks,
notes: ::std::vec::Vec<Self::NoteEnum>,
);
fn remove_note(&mut self, note_type: Self::NoteTypeEnum, id: u64);
fn remove_notes(&mut self, notes: ::std::vec::Vec<(u64, Self::NoteTypeEnum)>);
fn all_notes(&self) -> impl Iterator<Item = Self::NoteSnapshotEnum>;
fn all_notes_of_type(
&self,
note_type: Self::NoteTypeEnum,
) -> impl Iterator<Item = Self::NoteSnapshotEnum>;
fn all_notes_ref_of_type<'a>(
&'a self,
note_type: Self::NoteTypeEnum,
) -> impl Iterator<Item = Self::NoteRefEnum<'a>> + 'a
where
Self: 'a;
fn all_notes_mut_of_type(
&mut self,
note_type: Self::NoteTypeEnum,
f: impl FnMut(Self::NoteMutEnum<'_>),
);
fn query_notes(
&self,
ids: impl Iterator<Item = (u64, Self::NoteTypeEnum)> + Clone,
) -> impl Iterator<Item = Self::NoteSnapshotEnum>;
fn query_notes_ref<'a>(
&'a self,
ids: impl Iterator<Item = (u64, Self::NoteTypeEnum)> + Clone + 'a,
) -> impl Iterator<Item = Self::NoteRefEnum<'a>> + 'a
where
Self: 'a;
fn query_notes_mut(
&mut self,
ids: impl Iterator<Item = (u64, Self::NoteTypeEnum)> + Clone,
f: impl FnMut(Self::NoteMutEnum<'_>),
);
fn notes_overlapping_range(
&self,
range: crate::notes::Interval<crate::rhythm::ClockTime>,
) -> impl Iterator<Item = Self::NoteSnapshotEnum>;
fn notes_ref_overlapping_range<'a>(
&'a self,
range: crate::notes::Interval<crate::rhythm::ClockTime>,
) -> impl Iterator<Item = Self::NoteRefEnum<'a>> + 'a
where
Self: 'a;
fn notes_mut_overlapping_range(
&mut self,
range: crate::notes::Interval<crate::rhythm::ClockTime>,
f: impl FnMut(Self::NoteMutEnum<'_>),
);
fn extract_notes(
&mut self,
notes: ::std::vec::Vec<(u64, Self::NoteTypeEnum)>,
f: impl FnMut(Self::NoteSnapshotEnum),
);
fn replace_note<G: crate::notes::NoteGroup>(
&mut self,
note_groups: &mut crate::notes::NoteGroups<G>,
tempo_tracks: &mut crate::rhythm::TempoTracks,
scroll_tracks: &mut crate::rhythm::ScrollSpeedTracks,
id: u64,
note: Self::NoteEnum,
);
fn replace_notes<G: crate::notes::NoteGroup>(
&mut self,
note_groups: &mut crate::notes::NoteGroups<G>,
tempo_tracks: &mut crate::rhythm::TempoTracks,
scroll_tracks: &mut crate::rhythm::ScrollSpeedTracks,
notes: ::std::vec::Vec<(u64, Self::NoteEnum)>,
);
}
#[allow(unused_variables)]
pub trait NotesStorageEditHook<S: NotesStorage> {
fn post_rebuild_clock_time(&mut self, storage: &mut S) {}
fn post_rebuild_scroll_pos(&mut self, storage: &mut S) {}
fn pre_add(&mut self, storage: &mut S, notes: &mut [S::NoteEnum]) {}
fn post_add(&mut self, storage: &mut S, notes: &[(u64, S::NoteTypeEnum)]) {}
fn pre_remove(&mut self, storage: &mut S, notes: &[S::NoteSnapshotEnum]) {}
fn post_remove(&mut self, storage: &mut S, notes: &[S::NoteSnapshotEnum]) {}
fn pre_update(&mut self, storage: &mut S, notes: &mut [(u64, S::NoteEnum)]) {}
fn post_update(
&mut self,
storage: &mut S,
notes: &[(S::NoteSnapshotEnum, S::NoteSnapshotEnum)],
) {
}
}
impl<S: NotesStorage> NotesStorageEditHook<S> for () {}
impl<S: NotesStorage, H: NotesStorageEditHook<S>, T: NotesStorageEditHook<S>>
NotesStorageEditHook<S> for (H, T)
{
fn post_rebuild_clock_time(&mut self, storage: &mut S) {
self.0.post_rebuild_clock_time(storage);
self.1.post_rebuild_clock_time(storage);
}
fn post_rebuild_scroll_pos(&mut self, storage: &mut S) {
self.0.post_rebuild_scroll_pos(storage);
self.1.post_rebuild_scroll_pos(storage);
}
fn pre_add(&mut self, storage: &mut S, notes: &mut [S::NoteEnum]) {
self.0.pre_add(storage, notes);
self.1.pre_add(storage, notes);
}
fn post_add(&mut self, storage: &mut S, notes: &[(u64, S::NoteTypeEnum)]) {
self.0.post_add(storage, notes);
self.1.post_add(storage, notes);
}
fn pre_remove(&mut self, storage: &mut S, notes: &[S::NoteSnapshotEnum]) {
self.0.pre_remove(storage, notes);
self.1.pre_remove(storage, notes);
}
fn post_remove(&mut self, storage: &mut S, notes: &[S::NoteSnapshotEnum]) {
self.0.post_remove(storage, notes);
self.1.post_remove(storage, notes);
}
fn pre_update(&mut self, storage: &mut S, notes: &mut [(u64, S::NoteEnum)]) {
self.0.pre_update(storage, notes);
self.1.pre_update(storage, notes);
}
fn post_update(
&mut self,
storage: &mut S,
notes: &[(S::NoteSnapshotEnum, S::NoteSnapshotEnum)],
) {
self.0.post_update(storage, notes);
self.1.post_update(storage, notes);
}
}