use super::*;
pub trait InputKind {
type Array: ArrayKind;
type Reader: SourceRead<Self>;
fn new_reader(&self, acc: &Accessor) -> Option<Self::Reader>;
}
pub trait SourceRead<K: InputKind + ?Sized>: Sized {
type Output: Clone;
fn load(&self, data: &[<K::Array as ArrayKind>::Elem]) -> Self::Output;
}
#[derive(Copy, Clone, Debug)]
pub struct Map<R, F> {
reader: R,
f: F,
}
impl<K: InputKind, R: SourceRead<K>, O: Clone, F: Fn(R::Output) -> O> SourceRead<K> for Map<R, F> {
type Output = O;
fn load(&self, data: &[<K::Array as ArrayKind>::Elem]) -> Self::Output {
(self.f)(self.reader.load(data))
}
}
impl Accessor {
pub fn param_offset(&self, name: &str, ty: &str) -> Option<usize> {
let pos = self
.param
.iter()
.position(|p| p.name.as_deref() == Some(name) && p.ty == ty)?;
Some(self.offset + pos)
}
}
#[derive(Clone, Debug)]
pub struct SourceReader<'a, K: InputKind, R = <K as InputKind>::Reader> {
kind: K,
array: &'a [<K::Array as ArrayKind>::Elem],
stride: usize,
len: usize,
reader: R,
}
impl Source {
pub fn reader<K: InputKind>(&self, kind: K) -> Option<SourceReader<'_, K>> {
let arr = self.array.as_ref()?;
if matches!((arr.id(), &self.accessor.source), (Some(id), Url::Fragment(s)) if s == id) {
let array = K::Array::from_array_element(arr)?;
debug_assert!(self.accessor.count * self.accessor.stride == array.len());
Some(SourceReader {
reader: kind.new_reader(&self.accessor)?,
kind,
array,
stride: self.accessor.stride,
len: self.accessor.count,
})
} else {
None }
}
}
impl<'a, K: InputKind, R: SourceRead<K>> SourceReader<'a, K, R> {
pub fn map_reader<S: SourceRead<K>>(self, f: impl FnOnce(R) -> S) -> SourceReader<'a, K, S> {
SourceReader {
kind: self.kind,
array: self.array,
stride: self.stride,
len: self.len,
reader: f(self.reader),
}
}
pub fn map<O: Clone, F: Fn(R::Output) -> O>(self, f: F) -> SourceReader<'a, K, Map<R, F>> {
self.map_reader(|reader| Map { reader, f })
}
pub fn get(&self, i: usize) -> R::Output {
let elems = &self.array[i * self.stride..][..self.stride];
self.reader.load(elems)
}
pub fn advance_by(&mut self, n: usize) -> Result<(), usize> {
if n <= self.len {
self.array = &self.array[n * self.stride..];
Ok(())
} else {
Err(self.len)
}
}
pub fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
if n <= self.len {
self.array = &self.array[..self.array.len() - n * self.stride];
Ok(())
} else {
Err(self.len)
}
}
}
impl<'a, K: InputKind, R: SourceRead<K>> ExactSizeIterator for SourceReader<'a, K, R> {
fn len(&self) -> usize {
self.len
}
}
impl<'a, K: InputKind, R: SourceRead<K>> DoubleEndedIterator for SourceReader<'a, K, R> {
fn next_back(&mut self) -> Option<Self::Item> {
self.len = self.len.checked_sub(1)?;
let (left, right) = self.array.split_at(self.len);
self.array = left;
Some(self.reader.load(right))
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.advance_back_by(n).ok()?;
self.next_back()
}
}
impl<'a, K: InputKind, R: SourceRead<K>> Iterator for SourceReader<'a, K, R> {
type Item = R::Output;
fn next(&mut self) -> Option<Self::Item> {
self.len = self.len.checked_sub(1)?;
let (left, right) = self.array.split_at(self.stride);
self.array = right;
Some(self.reader.load(left))
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
fn count(self) -> usize {
self.len
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.advance_by(n).ok()?;
self.next()
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct XYZ;
impl InputKind for XYZ {
type Array = FloatArray;
type Reader = XYZReader;
fn new_reader(&self, acc: &Accessor) -> Option<Self::Reader> {
Some(XYZReader {
x: acc.param_offset("X", "float")?,
y: acc.param_offset("Y", "float")?,
z: acc.param_offset("Z", "float")?,
})
}
}
#[derive(Copy, Clone, Debug)]
pub struct XYZReader {
x: usize,
y: usize,
z: usize,
}
impl SourceRead<XYZ> for XYZReader {
type Output = [f32; 3];
fn load(&self, data: &[f32]) -> Self::Output {
[data[self.x], data[self.y], data[self.z]]
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct ST;
impl InputKind for ST {
type Array = FloatArray;
type Reader = STReader;
fn new_reader(&self, acc: &Accessor) -> Option<Self::Reader> {
Some(STReader {
s: acc.param_offset("S", "float")?,
t: acc.param_offset("T", "float")?,
})
}
}
#[derive(Copy, Clone, Debug)]
pub struct STReader {
s: usize,
t: usize,
}
impl SourceRead<ST> for STReader {
type Output = [f32; 2];
fn load(&self, data: &[f32]) -> Self::Output {
[data[self.s], data[self.t]]
}
}