use std::marker::PhantomData;
use furiosa_mapping::Mapping as MappingValue;
use furiosa_mapping::*;
use crate::backend::op_prep::{broadcast_axes, gather_params, scatter_params, transpose_broadcast};
use crate::scalar::*;
#[derive(Clone, Debug)]
pub struct PhantomStorage<D: Scalar> {
axes: Vec<AxisTerm>,
_phantom: PhantomData<D>,
}
impl<D: Scalar> PartialEq for PhantomStorage<D> {
fn eq(&self, other: &Self) -> bool {
self.axes == other.axes
}
}
impl<D: Scalar> Eq for PhantomStorage<D> {}
impl<D: Scalar> PhantomStorage<D> {
fn new<Mapping: M>() -> Self {
Self::new_from_axes(Mapping::to_value().axes())
}
fn new_from_axes(axes: Vec<AxisTerm>) -> Self {
Self {
axes,
_phantom: PhantomData,
}
}
pub(crate) fn map<D2: Scalar>(&self, _f: impl FnMut(D) -> D2) -> PhantomStorage<D2> {
PhantomStorage::new_from_axes(self.axes.clone())
}
pub(crate) fn zip_with<D2: Scalar, D3: Scalar>(
&self,
_other: &PhantomStorage<D2>,
_f: impl Fn(D, D2) -> D3,
) -> PhantomStorage<D3> {
PhantomStorage::new_from_axes(self.axes.clone())
}
pub(crate) fn zip3_with<D2: Scalar, D3: Scalar, D4: Scalar>(
&self,
_b: &PhantomStorage<D2>,
_c: &PhantomStorage<D3>,
_f: impl Fn(D, D2, D3) -> D4,
) -> PhantomStorage<D4> {
PhantomStorage::new_from_axes(self.axes.clone())
}
pub(crate) fn transpose<Src: M, Mapping: M>(
&mut self,
_src: &PhantomStorage<D>,
_src_offset: &Index,
_dst_offset: &Index,
allow_broadcast: bool,
) {
let _ = transpose_broadcast::<Src, Mapping>(allow_broadcast);
}
pub(crate) fn reduce<Src: M, Dst: M, R: Fn(D, D) -> D>(
&self,
_reduce_fn: R,
_identity: D,
allow_broadcast: bool,
) -> Self {
let src = Src::to_value();
let dst = Dst::to_value();
let broadcast = broadcast_axes(&src, &dst);
assert!(
allow_broadcast || broadcast.axes().is_empty(),
"reduce: Dst adds axes absent from the source; pass allow_broadcast=true for reduce-then-broadcast"
);
let inter = dst.carve(&broadcast);
let _reduce_residue = src.carve(&inter);
Self::new::<Dst>()
}
pub(crate) fn contraction(&self, _rhs: &Self, out: &MappingValue) -> Self {
Self::new_from_axes(out.axes())
}
#[expect(
clippy::extra_unused_type_parameters,
reason = "signature parity with Backend::scatter"
)]
pub(crate) fn scatter<Src: M, Key: M, Dst: M, Idx: M>(
&self,
_dst: &mut PhantomStorage<D>,
_index: &PhantomStorage<i32>,
_scaled: bool,
) {
let _ = scatter_params(&Src::to_value(), &Dst::to_value(), &Key::to_value());
}
pub(crate) fn gather<Src: M, Dst: M, Idx: M>(
&self,
_dst: &mut PhantomStorage<D>,
_index: &PhantomStorage<i32>,
_scaled: bool,
) {
let _ = gather_params(&Src::to_value(), &Dst::to_value(), &Idx::to_value());
}
pub(crate) fn reshape<Mapping: M, Mapping2: M>(&self) -> Self {
assert_eq!(Mapping::SIZE, Mapping2::SIZE);
Self::new::<Mapping2>()
}
pub(crate) fn from_vec(mapping: &MappingValue, _data: impl IntoIterator<Item = D>) -> Self {
Self::new_from_axes(mapping.axes())
}
pub(crate) fn into_vec(self, _mapping: &MappingValue) -> Vec<D> {
Vec::new()
}
pub(crate) fn uninit(mapping: &MappingValue) -> Self {
Self::new_from_axes(mapping.axes())
}
}