1use crate::dyn_backend::{DynBackendDevice, DynBackendStorage};
31use crate::inplace_op::{InplaceOp1, InplaceOp2, InplaceOp3};
32use fuel_ir::op::{self, BinaryOp, CmpOp, ReduceOp};
33use fuel_ir::storage::{OutputView, OutputViewSpec, compose_bundle};
34use fuel_ir::stype::SType;
35use fuel_ir::{DType, Error, HostBuffer, Layout, Result, Scalar, Shape, conv};
36use std::sync::Arc;
37
38pub fn allocate_bundled_storage(
48 device: &dyn DynBackendDevice,
49 specs: &[OutputViewSpec],
50) -> Result<Storage> {
51 let (total_bytes, views) = compose_bundle(specs)?;
52 let primary_dtype = specs[0].dtype;
53 let primary_size = primary_dtype.size_in_bytes().max(1);
54 let flat_elems = total_bytes.div_ceil(primary_size).max(1);
58 let inner = device.zeros_impl_dyn(&Shape::from_dims(&[flat_elems]), primary_dtype)?;
59 Storage::from_dyn_bundled(inner, Arc::from(views.into_boxed_slice()))
60}
61
62#[derive(Debug)]
75pub struct Storage {
76 pub(crate) inner: Box<dyn DynBackendStorage>,
77 pub(crate) bundle: Option<Arc<[OutputView]>>,
83 pub(crate) stype: SType,
89}
90
91impl Storage {
92 pub fn new<B: DynBackendStorage + 'static>(b: B) -> Self {
99 Storage {
100 inner: Box::new(b),
101 bundle: None,
102 stype: SType::default(),
103 }
104 }
105
106 pub fn from_dyn(b: Box<dyn DynBackendStorage>) -> Self {
111 Storage {
112 inner: b,
113 bundle: None,
114 stype: SType::default(),
115 }
116 }
117
118 pub fn from_dyn_bundled(
129 b: Box<dyn DynBackendStorage>,
130 bundle: Arc<[OutputView]>,
131 ) -> Result<Self> {
132 if bundle.is_empty() {
133 return Err(Error::Msg(
134 "Storage::from_dyn_bundled: bundle slice must be non-empty".into(),
135 )
136 .bt());
137 }
138 let primary = bundle[0].dtype;
139 let inner_dtype = b.dtype_dyn();
140 if primary != inner_dtype {
141 return Err(Error::Msg(format!(
142 "Storage::from_dyn_bundled: slot 0 dtype {primary:?} must \
143 match inner backend dtype {inner_dtype:?}",
144 ))
145 .bt());
146 }
147 Ok(Storage {
148 inner: b,
149 bundle: Some(bundle),
150 stype: SType::default(),
151 })
152 }
153
154 pub fn with_bundle(mut self, bundle: Arc<[OutputView]>) -> Result<Self> {
159 debug_assert!(
160 self.bundle.is_none(),
161 "Storage::with_bundle: bundle already attached",
162 );
163 if bundle.is_empty() {
164 return Err(
165 Error::Msg("Storage::with_bundle: bundle slice must be non-empty".into()).bt(),
166 );
167 }
168 let primary = bundle[0].dtype;
169 let inner_dtype = self.inner.dtype_dyn();
170 if primary != inner_dtype {
171 return Err(Error::Msg(format!(
172 "Storage::with_bundle: slot 0 dtype {primary:?} must \
173 match inner backend dtype {inner_dtype:?}",
174 ))
175 .bt());
176 }
177 self.bundle = Some(bundle);
178 Ok(self)
179 }
180
181 pub fn is_bundled(&self) -> bool {
183 self.bundle.is_some()
184 }
185
186 pub fn slot_count(&self) -> usize {
190 match &self.bundle {
191 Some(b) => b.len(),
192 None => 1,
193 }
194 }
195
196 pub fn bundle(&self) -> Option<&[OutputView]> {
199 self.bundle.as_deref()
200 }
201
202 pub fn bundle_arc(&self) -> Option<Arc<[OutputView]>> {
206 self.bundle.clone()
207 }
208
209 pub fn slot_view(&self, idx: usize) -> Option<&OutputView> {
215 self.bundle.as_deref().and_then(|b| b.get(idx))
216 }
217
218 pub fn primary_dtype(&self) -> DType {
224 self.inner.dtype_dyn()
225 }
226
227 pub fn slot_dtype(&self, idx: usize) -> Option<DType> {
232 self.slot_view(idx).map(|v| v.dtype)
233 }
234
235 pub fn as_dyn(&self) -> &dyn DynBackendStorage {
240 &*self.inner
241 }
242
243 pub fn as_dyn_mut(&mut self) -> &mut dyn DynBackendStorage {
245 &mut *self.inner
246 }
247
248 pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
250 self.inner.as_any().downcast_ref::<T>()
251 }
252
253 pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
255 self.inner.as_any_mut().downcast_mut::<T>()
256 }
257
258 pub fn try_clone(&self, layout: &Layout) -> Result<Self> {
259 Ok(Storage::from_dyn(self.inner.try_clone_dyn(layout)?).with_stype(self.stype.clone()))
263 }
264
265 pub fn device(&self) -> Arc<dyn DynBackendDevice> {
269 self.inner.device_arc_dyn()
270 }
271
272 pub fn dtype(&self) -> DType {
273 self.inner.dtype_dyn()
274 }
275
276 pub fn with_stype(mut self, stype: SType) -> Self {
280 self.stype = stype;
281 self
282 }
283
284 pub fn stype(&self) -> &SType {
286 &self.stype
287 }
288
289 pub fn same_device(&self, rhs: &Self, op: &'static str) -> Result<()> {
294 let lhs_dev = self.inner.device_dyn();
295 let rhs_dev = rhs.inner.device_dyn();
296 let lhs_loc = lhs_dev.location_dyn();
297 let rhs_loc = rhs_dev.location_dyn();
298 let same = if matches!(lhs_loc, fuel_ir::DeviceLocation::Metal { .. }) {
299 lhs_dev.same_device_dyn(rhs_dev)
301 } else {
302 lhs_loc == rhs_loc
303 };
304 if !same {
305 Err(Error::DeviceMismatchBinaryOp {
306 lhs: lhs_loc,
307 rhs: rhs_loc,
308 op,
309 }
310 .bt())
311 } else {
312 Ok(())
313 }
314 }
315
316 pub fn same_dtype(&self, rhs: &Self, op: &'static str) -> Result<()> {
317 let lhs = self.dtype();
318 let rhs = rhs.dtype();
319 if lhs != rhs {
320 Err(Error::DTypeMismatchBinaryOp { lhs, rhs, op }.bt())
321 } else {
322 Ok(())
323 }
324 }
325
326 pub fn const_set(&mut self, v: Scalar, l: &Layout) -> Result<()> {
327 self.inner.const_set_dyn(v, l)
328 }
329
330 pub fn affine(&self, layout: &Layout, mul: f64, add: f64) -> Result<Self> {
331 Ok(Storage::from_dyn(self.inner.affine_dyn(layout, mul, add)?))
332 }
333
334 pub fn powf(&self, layout: &Layout, e: f64) -> Result<Self> {
335 Ok(Storage::from_dyn(self.inner.powf_dyn(layout, e)?))
336 }
337
338 pub fn elu(&self, layout: &Layout, alpha: f64) -> Result<Self> {
339 Ok(Storage::from_dyn(self.inner.elu_dyn(layout, alpha)?))
340 }
341
342 pub fn cmp(
343 &self,
344 op: CmpOp,
345 rhs: &Self,
346 lhs_layout: &Layout,
347 rhs_layout: &Layout,
348 ) -> Result<Self> {
349 Ok(Storage::from_dyn(self.inner.cmp_dyn(
350 op,
351 &*rhs.inner,
352 lhs_layout,
353 rhs_layout,
354 )?))
355 }
356
357 pub fn reduce_op(&self, op: ReduceOp, layout: &Layout, reduce_dims: &[usize]) -> Result<Self> {
358 Ok(Storage::from_dyn(self.inner.reduce_op_dyn(
359 op,
360 layout,
361 reduce_dims,
362 )?))
363 }
364
365 pub fn to_dtype(&self, layout: &Layout, dtype: DType) -> Result<Self> {
366 Ok(Storage::from_dyn(self.inner.to_dtype_dyn(layout, dtype)?))
367 }
368
369 pub fn to_cpu_storage(&self) -> Result<HostBuffer> {
370 self.inner.to_host_buffer_dyn()
371 }
372
373 pub fn inplace_op1(&mut self, l: &Layout, c: &dyn InplaceOp1) -> Result<()> {
374 c.fwd(&mut *self.inner, l)
375 }
376
377 pub fn inplace_op2(
378 &mut self,
379 l1: &Layout,
380 t2: &Self,
381 l2: &Layout,
382 c: &dyn InplaceOp2,
383 ) -> Result<()> {
384 self.same_device(t2, c.name())?;
385 c.fwd(&mut *self.inner, l1, &*t2.inner, l2)
386 }
387
388 pub fn inplace_op3(
389 &mut self,
390 l1: &Layout,
391 t2: &Self,
392 l2: &Layout,
393 t3: &Self,
394 l3: &Layout,
395 c: &dyn InplaceOp3,
396 ) -> Result<()> {
397 self.same_device(t2, c.name())?;
398 self.same_device(t3, c.name())?;
399 c.fwd(&mut *self.inner, l1, &*t2.inner, l2, &*t3.inner, l3)
400 }
401
402 pub fn unary_impl<B: op::UnaryOpT>(&self, layout: &Layout) -> Result<Self> {
407 let op = op::UnaryOp::from_name(B::NAME)
408 .ok_or_else(|| Error::Msg(format!("unknown unary op '{}'", B::NAME)))?;
409 Ok(Storage::from_dyn(self.inner.unary_op_dyn(layout, op)?))
410 }
411
412 pub fn binary_impl<B: op::BinaryOpT>(
413 &self,
414 rhs: &Self,
415 lhs_layout: &Layout,
416 rhs_layout: &Layout,
417 ) -> Result<Self> {
418 self.same_device(rhs, B::NAME)?;
419 self.same_dtype(rhs, B::NAME)?;
420 let op = BinaryOp::from_name(B::NAME)
421 .ok_or_else(|| Error::Msg(format!("unknown binary op '{}'", B::NAME)))?;
422 Ok(Storage::from_dyn(self.inner.binary_op_dyn(
423 &*rhs.inner,
424 lhs_layout,
425 rhs_layout,
426 op,
427 )?))
428 }
429
430 pub fn conv1d(
435 &self,
436 l: &Layout,
437 kernel: &Self,
438 kernel_l: &Layout,
439 params: &conv::ParamsConv1D,
440 ) -> Result<Self> {
441 self.same_device(kernel, "conv1d")?;
442 self.same_dtype(kernel, "conv1d")?;
443 Ok(Storage::from_dyn(self.inner.conv1d_dyn(
444 l,
445 &*kernel.inner,
446 kernel_l,
447 params,
448 )?))
449 }
450
451 pub fn conv_transpose1d(
452 &self,
453 l: &Layout,
454 kernel: &Self,
455 kernel_l: &Layout,
456 params: &conv::ParamsConvTranspose1D,
457 ) -> Result<Self> {
458 self.same_device(kernel, "conv-transpose1d")?;
459 self.same_dtype(kernel, "conv-transpose1d")?;
460 Ok(Storage::from_dyn(self.inner.conv_transpose1d_dyn(
461 l,
462 &*kernel.inner,
463 kernel_l,
464 params,
465 )?))
466 }
467
468 pub fn conv2d(
469 &self,
470 l: &Layout,
471 kernel: &Self,
472 kernel_l: &Layout,
473 params: &conv::ParamsConv2D,
474 ) -> Result<Self> {
475 self.same_device(kernel, "conv2d")?;
476 self.same_dtype(kernel, "conv2d")?;
477 Ok(Storage::from_dyn(self.inner.conv2d_dyn(
478 l,
479 &*kernel.inner,
480 kernel_l,
481 params,
482 )?))
483 }
484
485 pub fn conv_transpose2d(
486 &self,
487 l: &Layout,
488 kernel: &Self,
489 kernel_l: &Layout,
490 params: &conv::ParamsConvTranspose2D,
491 ) -> Result<Self> {
492 self.same_device(kernel, "conv_transpose2d")?;
493 self.same_dtype(kernel, "conv_transpose2d")?;
494 Ok(Storage::from_dyn(self.inner.conv_transpose2d_dyn(
495 l,
496 &*kernel.inner,
497 kernel_l,
498 params,
499 )?))
500 }
501
502 pub fn avg_pool2d(
503 &self,
504 layout: &Layout,
505 kernel_size: (usize, usize),
506 stride: (usize, usize),
507 ) -> Result<Self> {
508 Ok(Storage::from_dyn(self.inner.avg_pool2d_dyn(
509 layout,
510 kernel_size,
511 stride,
512 )?))
513 }
514
515 pub fn max_pool2d(
516 &self,
517 layout: &Layout,
518 kernel_size: (usize, usize),
519 stride: (usize, usize),
520 ) -> Result<Self> {
521 Ok(Storage::from_dyn(self.inner.max_pool2d_dyn(
522 layout,
523 kernel_size,
524 stride,
525 )?))
526 }
527
528 pub fn upsample_nearest1d(&self, layout: &Layout, sz: usize) -> Result<Self> {
529 Ok(Storage::from_dyn(
530 self.inner.upsample_nearest1d_dyn(layout, sz)?,
531 ))
532 }
533
534 pub fn upsample_nearest2d(&self, layout: &Layout, h: usize, w: usize) -> Result<Self> {
535 Ok(Storage::from_dyn(
536 self.inner.upsample_nearest2d_dyn(layout, h, w)?,
537 ))
538 }
539
540 pub fn upsample_bilinear2d(
541 &self,
542 layout: &Layout,
543 h: usize,
544 w: usize,
545 align_corners: bool,
546 scale_h: Option<f64>,
547 scale_w: Option<f64>,
548 ) -> Result<Self> {
549 Ok(Storage::from_dyn(self.inner.upsample_bilinear2d_dyn(
550 layout,
551 h,
552 w,
553 align_corners,
554 scale_h,
555 scale_w,
556 )?))
557 }
558
559 pub fn where_cond(
564 &self,
565 layout: &Layout,
566 t: &Self,
567 layout_t: &Layout,
568 f: &Self,
569 layout_f: &Layout,
570 ) -> Result<Self> {
571 self.same_device(t, "where")?;
572 self.same_device(f, "where")?;
573 t.same_dtype(f, "where")?;
574 Ok(Storage::from_dyn(self.inner.where_cond_dyn(
575 layout, &*t.inner, layout_t, &*f.inner, layout_f,
576 )?))
577 }
578
579 pub fn gather(&self, l: &Layout, indexes: &Self, indexes_l: &Layout, d: usize) -> Result<Self> {
580 self.same_device(indexes, "index-add")?;
581 Ok(Storage::from_dyn(self.inner.gather_dyn(
582 l,
583 &*indexes.inner,
584 indexes_l,
585 d,
586 )?))
587 }
588
589 pub fn scatter_set(
590 &mut self,
591 l: &Layout,
592 indexes: &Self,
593 indexes_l: &Layout,
594 source: &Self,
595 source_l: &Layout,
596 d: usize,
597 ) -> Result<()> {
598 self.same_device(indexes, "scatter-set")?;
599 self.same_device(source, "scatter-set")?;
600 self.inner
601 .scatter_set_dyn(l, &*source.inner, source_l, &*indexes.inner, indexes_l, d)
602 }
603
604 pub fn scatter_add(
605 &mut self,
606 l: &Layout,
607 indexes: &Self,
608 indexes_l: &Layout,
609 source: &Self,
610 source_l: &Layout,
611 d: usize,
612 ) -> Result<()> {
613 self.same_device(indexes, "scatter-add")?;
614 self.same_device(source, "scatter-add")?;
615 self.inner
616 .scatter_add_set_dyn(l, &*source.inner, source_l, &*indexes.inner, indexes_l, d)
617 }
618
619 pub fn index_add(
620 &self,
621 l: &Layout,
622 indexes: &Self,
623 indexes_l: &Layout,
624 source: &Self,
625 source_l: &Layout,
626 d: usize,
627 ) -> Result<Self> {
628 self.same_device(indexes, "index-add")?;
629 self.same_device(source, "index-add")?;
630 Ok(Storage::from_dyn(self.inner.index_add_dyn(
631 l,
632 &*indexes.inner,
633 indexes_l,
634 &*source.inner,
635 source_l,
636 d,
637 )?))
638 }
639
640 pub fn index_select(
641 &self,
642 rhs: &Self,
643 lhs_l: &Layout,
644 rhs_l: &Layout,
645 d: usize,
646 ) -> Result<Self> {
647 self.same_device(rhs, "index-select")?;
648 Ok(Storage::from_dyn(self.inner.index_select_dyn(
649 &*rhs.inner,
650 lhs_l,
651 rhs_l,
652 d,
653 )?))
654 }
655
656 pub fn matmul(
661 &self,
662 rhs: &Self,
663 bmnk: (usize, usize, usize, usize),
664 lhs_layout: &Layout,
665 rhs_layout: &Layout,
666 ) -> Result<Self> {
667 self.same_device(rhs, "matmul")?;
668 self.same_dtype(rhs, "matmul")?;
669 Ok(Storage::from_dyn(self.inner.matmul_dyn(
670 &*rhs.inner,
671 bmnk,
672 lhs_layout,
673 rhs_layout,
674 )?))
675 }
676
677 pub fn copy_strided_src(
679 &self,
680 dst: &mut Self,
681 dst_offset: usize,
682 src_l: &Layout,
683 ) -> Result<()> {
684 self.inner
685 .copy_strided_src_dyn(&mut *dst.inner, dst_offset, src_l)
686 }
687
688 pub fn copy2d(
689 &self,
690 dst: &mut Self,
691 d1: usize,
692 d2: usize,
693 src_s: usize,
694 dst_s: usize,
695 src_o: usize,
696 dst_o: usize,
697 ) -> Result<()> {
698 self.inner
699 .copy2d_dyn(&mut *dst.inner, d1, d2, src_s, dst_s, src_o, dst_o)
700 }
701}
702
703#[cfg(test)]
704mod multi_output_specs {
705 use super::*;
706
707 fn f32_spec(dims: &[usize]) -> OutputViewSpec {
709 OutputViewSpec::contiguous(DType::F32, Shape::from_dims(dims))
710 }
711
712 fn f64_spec(dims: &[usize]) -> OutputViewSpec {
714 OutputViewSpec::contiguous(DType::F64, Shape::from_dims(dims))
715 }
716
717 #[test]
721 fn compose_bundle_single_slot() {
722 let specs = vec![f32_spec(&[2, 3])];
723 let (total, views) = compose_bundle(&specs).expect("single slot composes");
724 assert_eq!(views.len(), 1);
725 assert_eq!(views[0].byte_offset, 0);
726 assert_eq!(views[0].len_elements, 6);
727 assert_eq!(views[0].dtype, DType::F32);
728 assert_eq!(total, 24); }
730
731 #[test]
736 fn compose_bundle_two_slot_aligned() {
737 let specs = vec![f32_spec(&[2, 3]), f64_spec(&[3])];
738 let (total, views) = compose_bundle(&specs).expect("aligned compose");
739 assert_eq!(views.len(), 2);
740 assert_eq!(views[0].byte_offset, 0);
741 assert_eq!(views[0].len_elements, 6);
742 assert_eq!(views[1].byte_offset, 24);
743 assert_eq!(views[1].len_elements, 3);
744 assert_eq!(views[1].dtype, DType::F64);
745 assert_eq!(total, 48); }
747
748 #[test]
752 fn compose_bundle_pads_for_alignment() {
753 let specs = vec![f32_spec(&[1]), f64_spec(&[1])];
754 let (total, views) = compose_bundle(&specs).expect("padded compose");
755 assert_eq!(views[0].byte_offset, 0);
756 assert_eq!(views[1].byte_offset, 8); assert_eq!(total, 16); }
759
760 #[test]
762 fn compose_bundle_rejects_empty() {
763 let err = compose_bundle(&[]).expect_err("empty spec list must error");
764 assert!(format!("{err}").contains("non-empty"));
765 }
766
767 #[test]
770 fn compose_bundle_rejects_shape_layout_mismatch() {
771 let s = Shape::from_dims(&[2, 3]);
772 let bogus_layout = Layout::contiguous(Shape::from_dims(&[3, 2]));
773 let bad = OutputViewSpec {
774 dtype: DType::F32,
775 shape: s,
776 layout: bogus_layout,
777 name: None,
778 };
779 let err = compose_bundle(&[bad]).expect_err("shape/layout mismatch must error");
780 assert!(format!("{err}").contains("disagrees"));
781 }
782
783 #[test]
785 fn output_view_spec_contiguous_helper() {
786 let s = f32_spec(&[4, 5]);
787 assert_eq!(s.dtype, DType::F32);
788 assert_eq!(s.shape, Shape::from_dims(&[4, 5]));
789 assert_eq!(s.layout.shape(), &Shape::from_dims(&[4, 5]));
790 assert_eq!(s.elem_count(), 20);
791 assert_eq!(s.len_bytes(), 80);
792 assert!(s.name.is_none());
793 }
794}
795
796#[cfg(test)]
797mod stype_attach {
798 use super::*;
803 use fuel_ir::op::UnaryOp;
804 use std::any::Any;
805
806 #[derive(Debug)]
810 struct MockStorage;
811
812 #[allow(unused_variables)]
813 impl DynBackendStorage for MockStorage {
814 fn try_clone_dyn(&self, _layout: &Layout) -> Result<Box<dyn DynBackendStorage>> {
815 Ok(Box::new(MockStorage))
816 }
817 fn dtype_dyn(&self) -> DType {
818 DType::F32
819 }
820 fn as_any(&self) -> &dyn Any {
821 self
822 }
823 fn as_any_mut(&mut self) -> &mut dyn Any {
824 self
825 }
826
827 fn device_dyn(&self) -> &dyn DynBackendDevice {
828 unimplemented!()
829 }
830 fn device_arc_dyn(&self) -> Arc<dyn DynBackendDevice> {
831 unimplemented!()
832 }
833 fn to_host_buffer_dyn(&self) -> Result<HostBuffer> {
834 unimplemented!()
835 }
836 fn affine_dyn(&self, l: &Layout, mul: f64, add: f64) -> Result<Box<dyn DynBackendStorage>> {
837 unimplemented!()
838 }
839 fn powf_dyn(&self, l: &Layout, e: f64) -> Result<Box<dyn DynBackendStorage>> {
840 unimplemented!()
841 }
842 fn elu_dyn(&self, l: &Layout, alpha: f64) -> Result<Box<dyn DynBackendStorage>> {
843 unimplemented!()
844 }
845 fn reduce_op_dyn(
846 &self,
847 op: ReduceOp,
848 l: &Layout,
849 axes: &[usize],
850 ) -> Result<Box<dyn DynBackendStorage>> {
851 unimplemented!()
852 }
853 fn cmp_dyn(
854 &self,
855 op: CmpOp,
856 rhs: &dyn DynBackendStorage,
857 ll: &Layout,
858 rl: &Layout,
859 ) -> Result<Box<dyn DynBackendStorage>> {
860 unimplemented!()
861 }
862 fn to_dtype_dyn(&self, l: &Layout, dtype: DType) -> Result<Box<dyn DynBackendStorage>> {
863 unimplemented!()
864 }
865 fn unary_op_dyn(&self, l: &Layout, op: UnaryOp) -> Result<Box<dyn DynBackendStorage>> {
866 unimplemented!()
867 }
868 fn binary_op_dyn(
869 &self,
870 rhs: &dyn DynBackendStorage,
871 ll: &Layout,
872 rl: &Layout,
873 op: BinaryOp,
874 ) -> Result<Box<dyn DynBackendStorage>> {
875 unimplemented!()
876 }
877 fn where_cond_dyn(
878 &self,
879 cl: &Layout,
880 t: &dyn DynBackendStorage,
881 tl: &Layout,
882 f: &dyn DynBackendStorage,
883 fl: &Layout,
884 ) -> Result<Box<dyn DynBackendStorage>> {
885 unimplemented!()
886 }
887 fn conv1d_dyn(
888 &self,
889 l: &Layout,
890 k: &dyn DynBackendStorage,
891 kl: &Layout,
892 p: &conv::ParamsConv1D,
893 ) -> Result<Box<dyn DynBackendStorage>> {
894 unimplemented!()
895 }
896 fn conv_transpose1d_dyn(
897 &self,
898 l: &Layout,
899 k: &dyn DynBackendStorage,
900 kl: &Layout,
901 p: &conv::ParamsConvTranspose1D,
902 ) -> Result<Box<dyn DynBackendStorage>> {
903 unimplemented!()
904 }
905 fn conv2d_dyn(
906 &self,
907 l: &Layout,
908 k: &dyn DynBackendStorage,
909 kl: &Layout,
910 p: &conv::ParamsConv2D,
911 ) -> Result<Box<dyn DynBackendStorage>> {
912 unimplemented!()
913 }
914 fn conv_transpose2d_dyn(
915 &self,
916 l: &Layout,
917 k: &dyn DynBackendStorage,
918 kl: &Layout,
919 p: &conv::ParamsConvTranspose2D,
920 ) -> Result<Box<dyn DynBackendStorage>> {
921 unimplemented!()
922 }
923 fn avg_pool2d_dyn(
924 &self,
925 l: &Layout,
926 k: (usize, usize),
927 s: (usize, usize),
928 ) -> Result<Box<dyn DynBackendStorage>> {
929 unimplemented!()
930 }
931 fn max_pool2d_dyn(
932 &self,
933 l: &Layout,
934 k: (usize, usize),
935 s: (usize, usize),
936 ) -> Result<Box<dyn DynBackendStorage>> {
937 unimplemented!()
938 }
939 fn upsample_nearest1d_dyn(
940 &self,
941 l: &Layout,
942 t: usize,
943 ) -> Result<Box<dyn DynBackendStorage>> {
944 unimplemented!()
945 }
946 fn upsample_nearest2d_dyn(
947 &self,
948 l: &Layout,
949 h: usize,
950 w: usize,
951 ) -> Result<Box<dyn DynBackendStorage>> {
952 unimplemented!()
953 }
954 fn upsample_bilinear2d_dyn(
955 &self,
956 l: &Layout,
957 h: usize,
958 w: usize,
959 ac: bool,
960 sh: Option<f64>,
961 sw: Option<f64>,
962 ) -> Result<Box<dyn DynBackendStorage>> {
963 unimplemented!()
964 }
965 fn gather_dyn(
966 &self,
967 sl: &Layout,
968 ids: &dyn DynBackendStorage,
969 il: &Layout,
970 dim: usize,
971 ) -> Result<Box<dyn DynBackendStorage>> {
972 unimplemented!()
973 }
974 fn scatter_set_dyn(
975 &mut self,
976 sl: &Layout,
977 src: &dyn DynBackendStorage,
978 srl: &Layout,
979 ids: &dyn DynBackendStorage,
980 il: &Layout,
981 dim: usize,
982 ) -> Result<()> {
983 unimplemented!()
984 }
985 fn scatter_add_set_dyn(
986 &mut self,
987 sl: &Layout,
988 src: &dyn DynBackendStorage,
989 srl: &Layout,
990 ids: &dyn DynBackendStorage,
991 il: &Layout,
992 dim: usize,
993 ) -> Result<()> {
994 unimplemented!()
995 }
996 fn index_select_dyn(
997 &self,
998 ids: &dyn DynBackendStorage,
999 sl: &Layout,
1000 il: &Layout,
1001 dim: usize,
1002 ) -> Result<Box<dyn DynBackendStorage>> {
1003 unimplemented!()
1004 }
1005 fn index_add_dyn(
1006 &self,
1007 sl: &Layout,
1008 ids: &dyn DynBackendStorage,
1009 il: &Layout,
1010 src: &dyn DynBackendStorage,
1011 srl: &Layout,
1012 dim: usize,
1013 ) -> Result<Box<dyn DynBackendStorage>> {
1014 unimplemented!()
1015 }
1016 fn matmul_dyn(
1017 &self,
1018 rhs: &dyn DynBackendStorage,
1019 bmnk: (usize, usize, usize, usize),
1020 ll: &Layout,
1021 rl: &Layout,
1022 ) -> Result<Box<dyn DynBackendStorage>> {
1023 unimplemented!()
1024 }
1025 fn copy_strided_src_dyn(
1026 &self,
1027 dst: &mut dyn DynBackendStorage,
1028 off: usize,
1029 sl: &Layout,
1030 ) -> Result<()> {
1031 unimplemented!()
1032 }
1033 fn copy2d_dyn(
1034 &self,
1035 dst: &mut dyn DynBackendStorage,
1036 d1: usize,
1037 d2: usize,
1038 ss1: usize,
1039 ds1: usize,
1040 so: usize,
1041 dofs: usize,
1042 ) -> Result<()> {
1043 unimplemented!()
1044 }
1045 fn const_set_dyn(&mut self, value: Scalar, l: &Layout) -> Result<()> {
1046 unimplemented!()
1047 }
1048 }
1049
1050 #[test]
1053 fn trait_object_storage_defaults_plain() {
1054 let s = Storage::new(MockStorage);
1055 assert!(
1056 s.stype().is_plain(),
1057 "default Storage must carry a plain SType"
1058 );
1059 assert_eq!(s.stype().layers().len(), 0);
1060 }
1061
1062 #[test]
1065 fn try_clone_preserves_stype() {
1066 use fuel_ir::GgmlDType;
1067 use fuel_ir::stype::Encoding;
1068 let s = Storage::new(MockStorage).with_stype(SType::from_layer(Encoding::GgmlBlock {
1069 ggml_dtype: GgmlDType::Q4_0,
1070 }));
1071 let layout = Layout::contiguous(Shape::from_dims(&[4]));
1072 let cloned = s.try_clone(&layout).expect("clone");
1073 assert_eq!(cloned.stype(), s.stype(), "try_clone must preserve stype");
1074 assert!(!cloned.stype().is_plain());
1075 }
1076}