use std::collections::HashMap;
use soa_rs::{Soa, SoaClone, Soars};
pub mod edit;
pub mod query;
#[cfg(test)]
mod test;
#[expect(unused)]
pub use edit::*;
pub use query::query_intersecting;
use crate::notes::{GroupId, LongNoteData};
use crate::rhythm::{BeatTime, ClockTime, ScrollPosition, Time, TrackId};
pub trait ShortNoteData {
type ValueData: Soars + SoaClone + Clone + 'static;
type RuntimeData: Soars + SoaClone + Clone + Default + 'static;
fn time(&self) -> Time;
fn group_id(&self) -> &GroupId;
fn value_data(&self) -> Self::ValueData;
fn reconstruct<'a>(
time: Time,
value_data: <Self::ValueData as Soars>::Ref<'a>,
group_id: GroupId,
) -> Self;
}
impl<N: ShortNoteData> LongNoteData for N {
type ValueData = <N as ShortNoteData>::ValueData;
type RuntimeData = <N as ShortNoteData>::RuntimeData;
fn start_time(&self) -> Time {
ShortNoteData::time(self)
}
fn duration(&self) -> Time {
match self.time() {
Time::Clock(_) => Time::Clock(ClockTime::ZERO),
Time::Beat(_) => Time::Beat(BeatTime::ZERO),
}
}
fn group_id(&self) -> &GroupId {
ShortNoteData::group_id(self)
}
fn value_data(&self) -> Self::ValueData {
ShortNoteData::value_data(self)
}
fn reconstruct<'a>(
start_time: Time,
_duration: Time,
value_data: <Self::ValueData as Soars>::Ref<'a>,
group_id: GroupId,
) -> Self {
ShortNoteData::reconstruct(start_time, value_data, group_id)
}
}
#[derive(Debug, Clone, Copy)]
struct NoteLocation {
group_index: usize,
index_in_time_sorted_group: usize,
index_in_scroll_sorted_group: usize,
}
#[derive(Clone)]
pub struct ShortNoteTypeStorage<Note: ShortNoteData> {
note_id_counter: u64,
note_id_lookup: HashMap<u64, NoteLocation>,
time_sorted_groups: Vec<ShortNoteGroup<Note>>,
scroll_sorted_groups: Vec<ShortNoteGroup<Note>>,
}
impl<N: std::fmt::Debug + ShortNoteData> std::fmt::Debug for ShortNoteTypeStorage<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ShortNoteTypeStorage")
.field("note_id_counter", &self.note_id_counter)
.field("note_id_lookup", &self.note_id_lookup)
.field("time_sorted_groups", &self.time_sorted_groups)
.field("scroll_sorted_groups", &self.scroll_sorted_groups)
.finish()
}
}
#[derive(Clone)]
pub struct ShortNoteGroup<Note: ShortNoteData> {
group_id: GroupId,
note_id: Vec<u64>,
time: Vec<Time>,
clock_time: Vec<ClockTime>,
scroll_position: Vec<ScrollPosition>,
value_data: Soa<Note::ValueData>,
runtime_data: Soa<Note::RuntimeData>,
}
impl<Note: ShortNoteData> std::fmt::Debug for ShortNoteGroup<Note> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ShortNoteGroup")
.field("note_id", &self.note_id)
.field("group_id", &self.group_id)
.field("time", &self.time)
.field("clock_time", &self.clock_time)
.field("scroll_position", &self.scroll_position)
.finish()
}
}
impl<Note: ShortNoteData> ShortNoteGroup<Note> {
pub fn new(group_id: GroupId) -> Self {
Self {
group_id,
note_id: vec![],
scroll_position: vec![],
time: vec![],
clock_time: vec![],
value_data: Default::default(),
runtime_data: Default::default(),
}
}
}
impl<Note: ShortNoteData> ShortNoteTypeStorage<Note> {
#[inline]
pub fn note_id(&self) -> impl Iterator<Item = u64> {
self.note_id_lookup.keys().copied()
}
#[inline]
pub fn time_sorted_groups(&self) -> &[ShortNoteGroup<Note>] {
&self.time_sorted_groups
}
#[inline]
pub fn scroll_sorted_groups(&self) -> &[ShortNoteGroup<Note>] {
&self.scroll_sorted_groups
}
}
impl<Note: ShortNoteData> ShortNoteGroup<Note> {
pub fn group_id(&self) -> &GroupId {
&self.group_id
}
pub fn note_id(&self) -> &[u64] {
&self.note_id
}
#[inline]
pub fn time(&self) -> &[Time] {
&self.time
}
#[inline]
pub fn clock_time(&self) -> &[ClockTime] {
&self.clock_time
}
#[inline]
pub fn value_data(&self) -> &Soa<Note::ValueData> {
&self.value_data
}
#[inline]
pub fn runtime_data(&self) -> &Soa<Note::RuntimeData> {
&self.runtime_data
}
#[inline]
pub fn scroll_position(&self) -> &[ScrollPosition] {
&self.scroll_position
}
}