pub struct Storage {
pub inner: BackendStorage,
pub dtype: DType,
pub bundle: Option<Arc<[OutputView]>>,
pub stype: SType,
}Expand description
Top-level storage type: byte-erased payload + runtime dtype tag.
Layout (shape + strides + start_offset) lives separately on the
consuming Tensor — Storage owns only the bytes and which
device/dtype they represent.
Optionally carries a bundle side-table describing how the inner
byte buffer is partitioned into multiple logically independent
outputs. Set by multi-output op authors via
Storage::with_bundle / Storage::new_bundled; consumed by
Op::View / Op::ViewOwned at realize time. See
OutputView.
Fields§
§inner: BackendStorageBackend variant + the bytes themselves.
dtype: DTypeHow to interpret the bytes. Storage’s len_bytes is the byte
count; the element count is len_bytes / dtype.size_in_bytes().
bundle: Option<Arc<[OutputView]>>None for single-output storage (today’s default). Some(_)
for multi-output bundles: a shared Arc’d slice of per-slot
OutputView entries, one per logical output. Op::View
nodes share this Arc so the bundle stays alive as long as any
view holds a reference.
stype: STypeHow the bytes are ENCODED (orthogonal to dtype, which is the
logical element type). Empty = plain dense dtype, byte-identical
to pre-SType behaviour. v1: PRIMARY storage only — bundle slots
keep dtype only (per-slot SType is a future addition). See
fuel_ir::SType and
docs/specs/storage-encoding.md.
Implementations§
Source§impl Storage
impl Storage
Sourcepub fn new(inner: BackendStorage, dtype: DType) -> Self
pub fn new(inner: BackendStorage, dtype: DType) -> Self
Build a Storage from an already-allocated backend variant
plus its dtype tag. Single-output (no bundle metadata); use
Self::with_bundle / Self::new_bundled for the
multi-output case.
Examples found in repository?
106fn main() {
107 println!(
108 "\n=== GAP-315 (d)-SIDE FORWARD TEST: Storage::with_bundle ===\n\
109 debug_assertions = {} ({})",
110 cfg!(debug_assertions),
111 if cfg!(debug_assertions) {
112 "ARM A - guard PRESENT (positive control)"
113 } else {
114 "ARM B - guard ABSENT (what the shipped artifact does)"
115 }
116 );
117
118 // CONTROL: the legitimate use — attach a bundle to an UNBUNDLED Storage.
119 // Must behave identically in both arms.
120 println!(
121 " [control] unbundled + with_bundle(2) -> {:?}",
122 probe(|| {
123 let s = Storage::new(
124 BackendStorage::Cpu(CpuStorageBytes::from_zero_bytes(64)),
125 DType::F32,
126 );
127 s.with_bundle(bundle_of(2))
128 })
129 );
130
131 // IN-PROBE CONTROL: the error path is LIVE. An empty bundle must be REJECTED
132 // in BOTH arms. Without this, a silent Ok below could be explained away as
133 // "nothing in this function can fail".
134 println!(
135 " [ctl-err] unbundled + EMPTY bundle -> {:?}",
136 probe(|| {
137 let s = Storage::new(
138 BackendStorage::Cpu(CpuStorageBytes::from_zero_bytes(64)),
139 DType::F32,
140 );
141 s.with_bundle(Arc::from(Vec::new().into_boxed_slice()))
142 })
143 );
144
145 // 🔴 THE PREDICTION: RE-BUNDLE. Storage already carries 3 slots; attach 2 more.
146 // Contract says re-bundling is a bug, so the callee owes a rejection.
147 // PREDICT arm B: Ok { slots: 2 } — the FIRST bundle (3 slots) silently gone.
148 println!(
149 " [rebundle] bundled(3) + with_bundle(2) -> {:?}",
150 probe(|| bundled(3).with_bundle(bundle_of(2)))
151 );
152
153 // Same violation, sizes swapped, so "slots" cannot be read as a coincidence.
154 println!(
155 " [rebundle2] bundled(2) + with_bundle(5) -> {:?}",
156 probe(|| bundled(2).with_bundle(bundle_of(5)))
157 );
158
159 println!(" (measurement only - asserts nothing)");
160}Sourcepub fn new_bundled(
inner: BackendStorage,
dtype: DType,
bundle: Arc<[OutputView]>,
) -> Result<Self>
pub fn new_bundled( inner: BackendStorage, dtype: DType, bundle: Arc<[OutputView]>, ) -> Result<Self>
Build a Storage from a backend variant + dtype tag + bundle side-table in one shot. Validates that the bundle is non-empty and that slot 0’s dtype matches the storage’s primary dtype (the bundled-storage invariant: slot 0 IS the primary).
Sourcepub fn with_bundle(self, bundle: Arc<[OutputView]>) -> Result<Self>
pub fn with_bundle(self, bundle: Arc<[OutputView]>) -> Result<Self>
Attach a bundle side-table to an existing single-output
Storage. Same validation as Self::new_bundled; panics in
debug mode if a bundle is already attached (re-bundling is a
contract bug).
Examples found in repository?
106fn main() {
107 println!(
108 "\n=== GAP-315 (d)-SIDE FORWARD TEST: Storage::with_bundle ===\n\
109 debug_assertions = {} ({})",
110 cfg!(debug_assertions),
111 if cfg!(debug_assertions) {
112 "ARM A - guard PRESENT (positive control)"
113 } else {
114 "ARM B - guard ABSENT (what the shipped artifact does)"
115 }
116 );
117
118 // CONTROL: the legitimate use — attach a bundle to an UNBUNDLED Storage.
119 // Must behave identically in both arms.
120 println!(
121 " [control] unbundled + with_bundle(2) -> {:?}",
122 probe(|| {
123 let s = Storage::new(
124 BackendStorage::Cpu(CpuStorageBytes::from_zero_bytes(64)),
125 DType::F32,
126 );
127 s.with_bundle(bundle_of(2))
128 })
129 );
130
131 // IN-PROBE CONTROL: the error path is LIVE. An empty bundle must be REJECTED
132 // in BOTH arms. Without this, a silent Ok below could be explained away as
133 // "nothing in this function can fail".
134 println!(
135 " [ctl-err] unbundled + EMPTY bundle -> {:?}",
136 probe(|| {
137 let s = Storage::new(
138 BackendStorage::Cpu(CpuStorageBytes::from_zero_bytes(64)),
139 DType::F32,
140 );
141 s.with_bundle(Arc::from(Vec::new().into_boxed_slice()))
142 })
143 );
144
145 // 🔴 THE PREDICTION: RE-BUNDLE. Storage already carries 3 slots; attach 2 more.
146 // Contract says re-bundling is a bug, so the callee owes a rejection.
147 // PREDICT arm B: Ok { slots: 2 } — the FIRST bundle (3 slots) silently gone.
148 println!(
149 " [rebundle] bundled(3) + with_bundle(2) -> {:?}",
150 probe(|| bundled(3).with_bundle(bundle_of(2)))
151 );
152
153 // Same violation, sizes swapped, so "slots" cannot be read as a coincidence.
154 println!(
155 " [rebundle2] bundled(2) + with_bundle(5) -> {:?}",
156 probe(|| bundled(2).with_bundle(bundle_of(5)))
157 );
158
159 println!(" (measurement only - asserts nothing)");
160}Sourcepub fn is_bundled(&self) -> bool
pub fn is_bundled(&self) -> bool
Whether this storage carries multi-output bundle metadata.
Sourcepub fn slot_count(&self) -> usize
pub fn slot_count(&self) -> usize
Number of logical output slots. 1 for single-output;
bundle.len() for bundled.
Sourcepub fn bundle(&self) -> Option<&[OutputView]>
pub fn bundle(&self) -> Option<&[OutputView]>
Borrow the bundle slice, or None for single-output storage.
Examples found in repository?
85fn probe<F: FnOnce() -> fuel_ir::Result<Storage> + std::panic::UnwindSafe>(f: F) -> Outcome {
86 let prev = std::panic::take_hook();
87 std::panic::set_hook(Box::new(|_| {}));
88 let r = std::panic::catch_unwind(f);
89 std::panic::set_hook(prev);
90 match r {
91 Err(p) => {
92 let msg = p
93 .downcast_ref::<String>()
94 .cloned()
95 .or_else(|| p.downcast_ref::<&str>().map(|s| (*s).to_string()))
96 .unwrap_or_else(|| "<non-string panic>".into());
97 Outcome::Panic(msg.lines().next().unwrap_or("").to_string())
98 }
99 Ok(Err(e)) => Outcome::Err(format!("{e}").lines().next().unwrap_or("").to_string()),
100 Ok(Ok(s)) => Outcome::Ok {
101 slots: s.bundle().map(|b| b.len()).unwrap_or(0),
102 },
103 }
104}Sourcepub fn slot_view(&self, idx: usize) -> Option<&OutputView>
pub fn slot_view(&self, idx: usize) -> Option<&OutputView>
Per-slot view; None for out-of-range or single-output.
Sourcepub fn elem_count(&self) -> usize
pub fn elem_count(&self) -> usize
Element count = len_bytes / dtype.size_in_bytes().
Sourcepub fn with_stype(self, stype: SType) -> Self
pub fn with_stype(self, stype: SType) -> Self
Attach an encoding scheme to this storage (consuming builder).
Does not touch the bytes or the logical dtype — only describes
HOW the bytes are encoded. See fuel_ir::SType.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Storage
impl RefUnwindSafe for Storage
impl Send for Storage
impl Sync for Storage
impl Unpin for Storage
impl UnsafeUnpin for Storage
impl UnwindSafe for Storage
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more