use std::borrow::Cow;
use std::fmt::Debug;
use std::ops::Range;
use super::{BorrowedReadPipeline, Item, OwnedReadPipeline, UniversalReadFs, UserData};
use crate::common::ext::aligned_vec::ACow;
use crate::common::generic_consts::{AccessPattern, Sequential};
use crate::common::universal_io::{ReadRange, Result, UniversalKind};
#[expect(clippy::len_without_is_empty)]
pub trait UniversalRead: Sized + Debug + Send + Sync {
type Fs: UniversalReadFs<File = Self>;
type BorrowedReadPipeline<'file, U>: BorrowedReadPipeline<'file, U, File = Self>
where
Self: 'file,
U: UserData;
type OwnedReadPipeline<U>: OwnedReadPipeline<U, File = Self>
where
U: UserData;
fn reopen(&mut self) -> Result<()>;
#[inline]
fn read<P: AccessPattern, T: Item>(&self, range: ReadRange) -> Result<Cow<'_, [T]>> {
let bytes = self.read_bytes::<P>(range.into_byte_range::<T>(), align_of::<T>())?;
Ok(bytes.try_cast_bytemuck().unwrap())
}
fn read_bytes<P: AccessPattern>(&self, range: Range<u64>, align: usize) -> Result<ACow<'_>>;
fn read_whole<T: Item>(&self) -> Result<Cow<'_, [T]>> {
let range = ReadRange {
byte_offset: 0,
length: self.len::<T>()?,
};
self.read::<Sequential, T>(range)
}
fn read_batch<P, T, U>(
&self,
ranges: impl IntoIterator<Item = (U, ReadRange)>,
mut callback: impl FnMut(U, &[T]) -> Result<()>,
) -> Result<()>
where
P: AccessPattern,
T: Item,
U: UserData,
{
for record in self.read_iter::<P, T, U>(ranges)? {
let (user_data, data) = record?;
callback(user_data, &data)?;
}
Ok(())
}
fn read_iter<P, T, U>(
&self,
ranges: impl IntoIterator<Item = (U, ReadRange)>,
) -> Result<impl Iterator<Item = Result<(U, Cow<'_, [T]>)>>>
where
P: AccessPattern,
T: Item,
U: UserData,
{
let reads = ranges
.into_iter()
.map(move |(user_data, range)| (user_data, self, range));
Self::read_multi_iter::<P, T, U>(reads)
}
fn len<T>(&self) -> Result<u64>;
fn populate(&self) -> Result<()>;
fn clear_ram_cache(&self) -> Result<()>;
fn read_multi<'a, P, T, U>(
reads: impl IntoIterator<Item = (U, &'a Self, ReadRange)>,
mut callback: impl FnMut(U, &[T]) -> Result<()>,
) -> Result<()>
where
P: AccessPattern,
T: Item,
U: UserData,
Self: 'a,
{
for record in Self::read_multi_iter::<P, T, U>(reads)? {
let (user_data, items) = record?;
callback(user_data, &items)?;
}
Ok(())
}
fn read_multi_iter<'a, P, T, U>(
reads: impl IntoIterator<Item = (U, &'a Self, ReadRange)>,
) -> Result<impl Iterator<Item = Result<(U, Cow<'a, [T]>)>>>
where
P: AccessPattern,
T: Item,
U: UserData,
Self: 'a,
{
let mut pipeline = Self::BorrowedReadPipeline::<'a, U>::new()?;
let mut reads = reads.into_iter();
let iter = std::iter::from_fn(move || {
while pipeline.can_schedule()
&& let Some(read) = reads.next()
{
let (user_data, file, range) = read;
let range = range.into_byte_range::<T>();
if let Err(err) = pipeline.schedule::<P>(user_data, file, range, align_of::<T>()) {
return Some(Err(err));
}
}
pipeline.wait_bytemuck().transpose()
});
Ok(iter)
}
fn kind() -> UniversalKind;
}