Skip to main content

fuel_tensor/
lib.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! `fuel-tensor` — Fuel's user-facing `Tensor` handle and `Device`
3//! abstraction, moved here from `fuel-core` (board #109; CireSnave:
4//! "Move Tensor into fuel-tensor. We can worry about a semantic split
5//! later."). This is a MECHANICAL move -- every item below kept its own
6//! content; only the crate boundary changed. `fuel-core`'s own
7//! `lib.rs` re-exports these same paths so existing
8//! `fuel_tensor::lazy::Tensor` / `fuel::Tensor` call sites keep compiling.
9//!
10//! The moved cluster (`lazy`, `device`, the 3 GPU backend bridges,
11//! `dtype`'s `WithDType`/`IntDType`/`FloatDType` trio, `pipelined_bridge`,
12//! `judge`, `factories`, `planner`, `decode_shape`, `lazy_latent_cache`,
13//! `test_utils`, `scheduling`, `inference_context`,
14//! `kv_block_pool_device`, `persistent_decode`, `nf4`) moved together in
15//! one PR because it is one mutually-referencing graph, not several
16//! independent files that happen to touch `Tensor` -- measured via a
17//! full crate::-reference census before any file moved, not assumed
18//! from file names. See `docs/release-0.13.0-wave.md`.
19//!
20//! ```rust
21//! use fuel_tensor::lazy::{Tensor, realize_many_f32};
22//! use fuel_tensor::Device;
23//! # use fuel_tensor::Error;
24//! # fn main() -> Result<(), Error> {
25//! let dev = Device::cpu();
26//! let a = Tensor::from_f32((0..6).map(|x| x as f32).collect::<Vec<_>>(), (2, 3), &dev)?;
27//! let b = Tensor::from_f32_on(a.graph(), (0..12).map(|x| x as f32).collect::<Vec<_>>(), (3, 4), &dev)?;
28//! let c = a.matmul(&b)?;
29//! assert_eq!(c.shape().dims(), &[2, 4]);
30//! let out = realize_many_f32(&[&c]);
31//! assert_eq!(out[0].len(), 8);
32//! # Ok(())}
33//! ```
34
35// GAP-229: `clippy::identity_op` fires across fuel-core+fuel-dispatch (and now
36// fuel-tensor, since the flagged sites in judge/mod.rs and lazy.rs moved here)
37// and is a defect in 0 of them — it measures a house idiom, not debt, so it is
38// allowed at the crate root. Carried forward verbatim from fuel-core/src/lib.rs
39// (board #109 move) rather than re-derived, since the measurement and the two
40// intentional classes it documents (DOC-INDEX, DOC-SHAPE) are about the CODE
41// that moved, not about which crate currently compiles it. See fuel-core's own
42// copy of this comment (unaffected by this move) for the full rationale.
43#![allow(clippy::identity_op)]
44
45pub mod awq;
46pub mod cuda_backend;
47pub mod decode_shape;
48pub mod device;
49pub mod dtype;
50pub mod factories;
51pub mod inference_context;
52pub mod judge;
53pub mod kv_block_pool_device;
54pub mod lazy;
55pub mod lazy_latent_cache;
56pub mod metal_backend;
57pub mod nf4;
58pub mod persistent_decode;
59pub mod pipelined_bridge;
60pub mod planner;
61pub mod reproducibility;
62pub mod scheduling;
63pub mod test_utils;
64#[cfg(feature = "vulkan")]
65pub mod vulkan_backend;
66
67pub use device::{Device, DeviceLocation, NdArray};
68pub use dtype::{DType, DTypeParseError, FloatDType, IntDType, WithDType};
69pub use fuel_ir::error::{Context, Error, Result};
70// `device.rs` uses `crate::Layout`/`crate::Shape` (root-qualified) internally;
71// these are the same fuel_ir re-exports fuel-core's own root carries, needed
72// here because fuel-tensor is now the crate device.rs's `crate::` resolves
73// within.
74pub use fuel_ir::layout::Layout;
75pub use fuel_ir::shape::{D, Shape};
76// device.rs's `use crate::{DType, HostBuffer, Result, Shape, Storage,
77// WithDType};` -- a GROUPED import, which an earlier `crate::X` text census
78// missed (it doesn't contain the substring `crate::HostBuffer`, only
79// `HostBuffer` inside `crate::{...}`'s braces). Caught by the first real
80// `cargo check`, not the census.
81pub use fuel_backend_contract::Storage;
82pub use fuel_ir::HostBuffer;
83
84#[doc(hidden)]
85#[cfg(feature = "cuda")]
86pub use cuda_backend as cuda;
87
88#[cfg(feature = "cuda")]
89pub use cuda_backend::{CudaDevice, CudaStorage};
90
91#[cfg(feature = "cuda")]
92pub use fuel_cuda_backend::builder_arg;
93
94#[cfg(feature = "metal")]
95pub use metal_backend::{MetalDevice, MetalError, MetalStorage};
96
97#[cfg(feature = "mkl")]
98extern crate intel_mkl_src;
99
100#[cfg(feature = "accelerate")]
101extern crate accelerate_src;
102
103// `bail!` consolidation (fuel-core dissolution, GAP-347 PR 4): this used to
104// be a LOCAL duplicate of `fuel_core::bail!`, kept separate only because
105// depending on `fuel_core::bail!` directly would have created a
106// `fuel-tensor` <-> `fuel-core` cargo cycle (`fuel-core` needs
107// `fuel-tensor` for `train.rs`). That reasoning never applied to
108// `fuel_ir`: this crate already depends on it directly (`Error`/`Result`
109// above are a bare re-export of `fuel_ir::error::{Error, Result}`, not a
110// distinct type), and `fuel_ir` is tier 10 — below everything. `$crate`
111// inside a `macro_rules!` body resolves to the crate that WROTE the
112// macro, not the one that re-exports or invokes it, so re-exporting here
113// keeps `fuel_tensor::bail!` producing byte-identical `fuel_ir::Error::Msg`
114// values — proved by the pre-existing `bail_tests::bail_macro_returns_a_typed_err`
115// below, which is unchanged and still exercises this re-export.
116pub use fuel_ir::bail;
117
118#[cfg(test)]
119mod bail_tests {
120    use crate::bail;
121    use fuel_ir::error::Result;
122
123    fn always_bails() -> Result<()> {
124        bail!("deliberate failure for the macro test");
125        #[allow(unreachable_code)]
126        Ok(())
127    }
128
129    #[test]
130    fn bail_macro_returns_a_typed_err() {
131        let err = always_bails().expect_err("bail! must produce an Err, never panic");
132        assert!(err.to_string().contains("deliberate failure"));
133    }
134}