#![feature(register_tool)]
#![register_tool(furiosa_opt)]
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![forbid(unused_must_use)]
pub use furiosa_mapping_macro::*;
pub use furiosa_mapping_types::*;
use abi_stable::std_types::{RResult, RSlice, RVec, Tuple2};
mod sys {
use super::*;
#[expect(improper_ctypes, reason = "all types are #[repr(C)] + StableAbi")]
unsafe extern "C-unwind" {
pub(super) fn mapping_sequence(
memories: RSlice<'_, Mapping>,
streams: RSlice<'_, Mapping>,
mode: SequencerMode,
) -> RResult<RVec<SequencerConfig>, SequencerError>;
pub(super) fn mapping_normalize(slf: &Mapping) -> Mapping;
pub(super) fn mapping_split_at(slf: &Mapping, target: usize) -> Tuple2<Mapping, Mapping>;
pub(super) fn mapping_index(slf: &Mapping, position: usize) -> Index;
pub(super) fn mapping_indexes(slf: &Mapping) -> RVec<Index>;
pub(super) fn mapping_axes(slf: &Mapping) -> RVec<Term>;
pub(super) fn index_finalize(slf: Index) -> RResult<RSortedMap<Ident, usize>, PaddingKind>;
pub(super) fn index_gen_indexes(slf: &Index, mapping: &Mapping) -> RVec<Index>;
}
}
pub trait MappingExt: Sized {
fn normalize(&self) -> Self;
fn is_resize_of(&self, original: &Self) -> bool;
fn split_at(&self, target: usize) -> (Self, Self);
fn index(&self, position: usize) -> Index;
fn indexes(&self) -> Vec<Index>;
fn axes(&self) -> Vec<Term>;
fn carve(&self, piece: &Self) -> Self;
}
pub fn sequence(
memories: &[&Mapping],
streams: &[&Mapping],
mode: SequencerMode,
) -> Result<Vec<SequencerConfig>, SequencerError> {
let memories: RVec<Mapping> = memories.iter().map(|m| (*m).clone()).collect();
let streams: RVec<Mapping> = streams.iter().map(|m| (*m).clone()).collect();
let configs = unsafe { sys::mapping_sequence(memories.as_rslice(), streams.as_rslice(), mode) }.into_result()?;
Ok(configs.into_iter().map(SequencerConfigExt::coalesce).collect())
}
impl MappingExt for Mapping {
fn normalize(&self) -> Self {
unsafe { sys::mapping_normalize(self) }
}
fn is_resize_of(&self, original: &Self) -> bool {
let n = self.size();
n <= original.size() && self.normalize() == original.clone().resize(n).normalize()
}
fn split_at(&self, target: usize) -> (Self, Self) {
let Tuple2(outer, inner) = unsafe { sys::mapping_split_at(self, target) };
(outer, inner)
}
fn index(&self, position: usize) -> Index {
unsafe { sys::mapping_index(self, position) }
}
fn indexes(&self) -> Vec<Index> {
unsafe { sys::mapping_indexes(self) }.into_iter().collect()
}
fn axes(&self) -> Vec<Term> {
unsafe { sys::mapping_axes(self) }.into_iter().collect()
}
fn carve(&self, piece: &Self) -> Self {
let configs = sequence(&[piece], &[self], SequencerMode::Read).expect("carve: piece must be contained in self");
let mut acc = Mapping::identity();
for (_key, entry) in configs[0].0.iter() {
let seg = if entry.memory_stride == 0 {
entry.mapping.clone()
} else {
Mapping::identity().padding(entry.mapping.size(), PaddingKind::Top)
};
acc = seg.pair(acc);
}
acc
}
}
pub trait SequencerConfigExt {
fn coalesce(self) -> Self;
}
impl SequencerConfigExt for SequencerConfig {
fn coalesce(self) -> SequencerConfig {
let mut out: Vec<(usize, SequencerEntry)> = Vec::new();
for (key, entry) in self.0 {
match out.last_mut() {
Some((_, run))
if run.memory_index == entry.memory_index
&& run.memory_stride * run.mapping.size() == entry.memory_stride =>
{
let inner = std::mem::replace(&mut run.mapping, Mapping::identity());
run.mapping = entry.mapping.pair(inner);
}
_ => out.push((key, entry)),
}
}
SequencerConfig(out.into_iter().collect())
}
}
pub trait IndexExt: Sized {
fn mark_invalid(&mut self);
fn add_mapping<I: crate::M>(&mut self, value: usize);
fn finalize(self) -> RResult<RSortedMap<Ident, usize>, PaddingKind>;
fn gen_indexes(&self, mapping: Mapping) -> RVec<Self>;
}
impl IndexExt for Index {
fn mark_invalid(&mut self) {
self.0 = RResult::RErr(PaddingKind::Bottom);
}
fn add_mapping<I: crate::M>(&mut self, value: usize) {
self.add(I::to_value().index(value));
}
fn finalize(self) -> RResult<RSortedMap<Ident, usize>, PaddingKind> {
unsafe { sys::index_finalize(self) }
}
fn gen_indexes(&self, mapping: Mapping) -> RVec<Self> {
unsafe { sys::index_gen_indexes(self, &mapping) }
}
}