Repository: coreylowman/dfdx (language: rust)

Issue:
Fix no-std support
Related to #612 

A few recent PRs are not no_std compatible. You can see the issues by running `cargo check --all --no-default-features -F no-std`.

This issue should go through and fix the issues found with the command above. It should mainly be imports


Discussion / hints:
This one is actually going to be kind of tough without excluding a lot of functionality from no-std environments.
What are you referring to? We require alloc support with no-std, so Vec/BTreeMap/String are all available, you just have to actually import them in no-std. I think some things like `.to_string()` might not exist, but you can use `.into()` for those iirc
Ah, nevermind then.

Fix patch:
diff --git a/.github/workflows/cargo-check-features.yml b/.github/workflows/cargo-check-features.yml
new file mode 100644
index 000000000..fc86b324d
--- /dev/null
+++ b/.github/workflows/cargo-check-features.yml
@@ -0,0 +1,25 @@
+on: [pull_request]
+
+jobs:
+  cargo-check-features:
+    name: cargo-check-features
+
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        config:
+          - toolchain: stable
+            command: cargo hack check --feature-powerset --no-dev-deps --depth 2 --skip default,nightly,cpu-mkl-matmul,cuda,test-cuda
+          - toolchain: nightly
+            command: cargo hack check --each-feature --no-dev-deps --features nightly --skip default,cpu-mkl-matmul,cuda,test-cuda
+
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: ${{ matrix.config.toolchain }}
+          override: true
+      - uses: taiki-e/install-action@cargo-hack
+      - name: Check Features Combinations
+        run: ${{ matrix.config.command }}
diff --git a/src/lib.rs b/src/lib.rs
index ae970c916..e20fe75ef 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -101,19 +101,16 @@
 //! mlp.zero_grads(&mut gradients);
 //! ```
 
-#![cfg_attr(feature = "no-std", no_std)]
+#![cfg_attr(all(feature = "no-std", not(feature = "std")), no_std)]
 #![allow(incomplete_features)]
 #![cfg_attr(feature = "nightly", feature(generic_const_exprs))]
 
 #[cfg(feature = "no-std")]
 #[macro_use]
 extern crate alloc;
-#[cfg(feature = "no-std")]
+#[cfg(all(feature = "no-std", not(feature = "std")))]
 extern crate no_std_compat as std;
 
-#[cfg(all(feature = "std", feature = "no-std"))]
-compile_error!("Can't enable both std and no-std. Set default-features = false to disable std");
-
 pub mod data;
 pub mod feature_flags;
 pub mod losses;
diff --git a/src/nn/impl_module_for_tuples.rs b/src/nn/impl_module_for_tuples.rs
index 171e68221..52cad942a 100644
--- a/src/nn/impl_module_for_tuples.rs
+++ b/src/nn/impl_module_for_tuples.rs
@@ -12,7 +12,7 @@ macro_rules! tuple_impls {
                 visitor: &mut V
             ) -> Result<Option<Self::To<V::E2, V::D2>>, V::Err> {
                 visitor.visit_fields(
-                    ($(Self::module(&std::format!("{}", $idx), |s| &s.$idx, |s| &mut s.$idx),)+),
+                    ($(Self::module(&format!("{}", $idx), |s| &s.$idx, |s| &mut s.$idx),)+),
                     |x| x
                 )
             }
diff --git a/src/nn/repeated.rs b/src/nn/repeated.rs
index 4e0e0b87d..dc8a0acb5 100644
--- a/src/nn/repeated.rs
+++ b/src/nn/repeated.rs
@@ -1,3 +1,5 @@
+use std::{string::String, vec::Vec};
+
 use crate::{shapes::Dtype, tensor_ops::Device};
 
 use super::*;
@@ -18,7 +20,7 @@ use super::*;
 /// ```
 #[derive(Debug, Clone)]
 pub struct Repeated<T, const N: usize> {
-    pub modules: std::vec::Vec<T>,
+    pub modules: Vec<T>,
 }
 
 impl<D: Device<E>, E: Dtype, T: BuildOnDevice<D, E>, const N: usize> BuildOnDevice<D, E>
@@ -35,7 +37,7 @@ impl<E: Dtype, D: Device<E>, T: TensorCollection<E, D>, const N: usize> TensorCo
     fn iter_tensors<V: ModuleVisitor<Self, E, D>>(
         visitor: &mut V,
     ) -> Result<Option<Self::To<V::E2, V::D2>>, V::Err> {
-        let names: Vec<String> = (0..N).map(|i| std::format!("{i}")).collect();
+        let names: Vec<String> = (0..N).map(|i| format!("{i}")).collect();
 
         visitor.visit_fields(
             (0..N)
diff --git a/src/nn/tensor_collection/visitor_impls.rs b/src/nn/tensor_collection/visitor_impls.rs
index b1645a16e..48612a7f0 100644
--- a/src/nn/tensor_collection/visitor_impls.rs
+++ b/src/nn/tensor_collection/visitor_impls.rs
@@ -1,4 +1,7 @@
-use std::vec::Vec;
+use std::{
+    string::{String, ToString},
+    vec::Vec,
+};
 
 use crate::{
     shapes::{Dtype, Shape},
@@ -122,10 +125,10 @@ impl TensorViewer for ViewTensorName {
         GetRef: FnMut(&Mod) -> &Field,
         GetMut: FnMut(&mut Mod) -> &mut Field,
     {
-        if !module.is_empty() {
-            std::format!("{module}.{name}")
-        } else {
+        if module.is_empty() {
             name.to_string()
+        } else {
+            format!("{module}.{name}")
         }
     }
 }
diff --git a/src/tensor/masks.rs b/src/tensor/masks.rs
index e476792f4..c65c9ddcb 100644
--- a/src/tensor/masks.rs
+++ b/src/tensor/masks.rs
@@ -14,7 +14,7 @@ use crate::prelude::{Shape, Unit};
 /// - `offset`: The offset from the main diagonal
 ///     - Positive values shift the diagonal in the `-M/+N` direction
 ///     - Negative values shift the diagonal in the `+M/-N` direction
-pub fn triangle_mask<S: Shape, E: Unit>(data: &mut Vec<E>, shape: &S, upper: bool, offset: isize) {
+pub fn triangle_mask<S: Shape, E: Unit>(data: &mut [E], shape: &S, upper: bool, offset: isize) {
     // Get the shape of the last two axes.
     let [num_rows, num_cols] = [
         (S::NUM_DIMS > 1)
@@ -27,7 +27,7 @@ pub fn triangle_mask<S: Shape, E: Unit>(data: &mut Vec<E>, shape: &S, upper: boo
     let mat_size = num_rows * num_cols;
 
     // Get the first 2D matrix in this data. This will be copied to each subsequent matrix.
-    let (mut mat2d, mut rest) = data.as_mut_slice().split_at_mut(mat_size);
+    let (mut mat2d, mut rest) = data.split_at_mut(mat_size);
     if upper {
         for r in (-offset).max(0) as usize..num_rows {
             for c in 0..((r as isize + offset).max(0) as usize).min(num_cols) {
diff --git a/src/tensor/storage_traits.rs b/src/tensor/storage_traits.rs
index 326c28c29..fb5fe9fa2 100644
--- a/src/tensor/storage_traits.rs
+++ b/src/tensor/storage_traits.rs
@@ -430,15 +430,7 @@ pub trait TensorFrom<Src, S: Shape, E: Unit>: DeviceStorage {
 
 impl<E: Unit, D: DeviceStorage + TensorFromVec<E>> TensorFrom<E, Rank0, E> for D {
     fn try_tensor(&self, src: E) -> Result<Tensor<Rank0, E, Self>, Self::Err> {
-        #[cfg(feature = "no-std")]
-        let buf = {
-            let mut buf = Vec::with_capacity(1);
-            buf.push(src);
-            buf
-        };
-        #[cfg(not(feature = "no-std"))]
-        let buf = vec![src];
-        self.try_tensor_from_vec(buf, ())
+        self.try_tensor_from_vec(vec![src], ())
     }
 }
 
diff --git a/src/tensor_ops/slice/cpu_kernel.rs b/src/tensor_ops/slice/cpu_kernel.rs
index c9f5cdb6e..8628d98fd 100644
--- a/src/tensor_ops/slice/cpu_kernel.rs
+++ b/src/tensor_ops/slice/cpu_kernel.rs
@@ -18,8 +18,6 @@ impl<E: Unit> SliceKernel<E> for Cpu {
             .get_strided_index(inp.shape.first_idx_in_slice(slice));
         let view = &inp.data[start_idx..];
 
-        println!("{} {}", start_idx, inp.shape.first_idx_in_slice(slice));
-
         while let Some((inp_i, o)) = inp_idx.next().zip(out_iter.next()) {
             *o = view[inp_i];
         }
@@ -30,8 +28,8 @@ impl<E: Unit> SliceKernel<E> for Cpu {
     fn backward<Src: Shape + SliceShape<Slice>, Slice>(
         &self,
         inp: &Tensor<Src, E, Self>,
-        grad_inp: &mut Vec<E>,
-        grad_out: &Vec<E>,
+        grad_inp: &mut Self::Vec<E>,
+        grad_out: &Self::Vec<E>,
         slice: &Slice,
     ) -> Result<(), Self::Err> {
         let dst = inp.shape.slice(slice).unwrap();


Test patch: