Repository: greyblake/nutype (language: rust)

Issue:
Fix support for `#![no_std]` and `serde`
Unable to compile in `#![no_std]` when using `serde` feature is enable and `std` feature is disabled.
The issue happens only with `Deserialize`.
I think the issue is the use of `std::marker` in the `gen_impl_trait_serde_deserialize` function, I'll make some tests and a PR asap.

using
```toml
[package]
name = "ttt"
version = "0.0.0"
edition = "2021"

[dependencies]
nutype = { version = "0.5.0", default-features = false, features = ["serde"] }
serde = { version = "1.0.210", default-features = false }
```

and 
```rs
#![no_std]
use nutype::nutype;

#[nutype(derive(Deserialize))]
struct A(f32);
```

I get
```
   Compiling ttt v0.0.0 (C:\Users\vic1707\Documents\Perso\ttt)
error[E0433]: failed to resolve: could not find `std` in the list of imported crates
 --> src\lib.rs:4:1
  |
4 | #[nutype(derive(Deserialize))]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not find `std` in the list of imported crates
  |
  = help: consider importing this module:
          core::marker
  = note: this error originates in the attribute macro `nutype` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0433`.
error: could not compile `ttt` (lib) due to 1 previous error
```

Whereas this works fine (after enabling the `derive` feature ofc).
```rs
#![no_std]
use serde::Deserialize;

#[derive(Deserialize)]
struct A(f32);
```


Discussion / hints:

Fix patch:
diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 00000000..2f9f13ae
--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,5 @@
+[build]
+rustflags = [
+    "-Dclippy::std_instead_of_core",
+    "-Dclippy::std_instead_of_alloc",
+]
diff --git a/examples/any_generics/src/main.rs b/examples/any_generics/src/main.rs
index 3c0c238d..6e41b183 100644
--- a/examples/any_generics/src/main.rs
+++ b/examples/any_generics/src/main.rs
@@ -1,6 +1,7 @@
 use nutype::nutype;
-use std::borrow::Cow;
-use std::cmp::Ord;
+extern crate alloc;
+use alloc::borrow::Cow;
+use core::cmp::Ord;
 
 /// A wrapper around a vector that is guaranteed to be sorted.
 #[nutype(
diff --git a/nutype_macros/src/any/models.rs b/nutype_macros/src/any/models.rs
index 894e4429..8b239e86 100644
--- a/nutype_macros/src/any/models.rs
+++ b/nutype_macros/src/any/models.rs
@@ -1,7 +1,7 @@
 use kinded::Kinded;
 use proc_macro2::TokenStream;
 use quote::ToTokens;
-use std::fmt::Debug;
+use core::fmt::Debug;
 use syn::Field;
 
 use crate::common::models::{CustomFunction, Guard, RawGuard, SpannedItem, TypeTrait};
diff --git a/nutype_macros/src/common/gen/mod.rs b/nutype_macros/src/common/gen/mod.rs
index 01da127b..fba0e4cb 100644
--- a/nutype_macros/src/common/gen/mod.rs
+++ b/nutype_macros/src/common/gen/mod.rs
@@ -4,7 +4,8 @@ pub mod parse_error;
 pub mod tests;
 pub mod traits;
 
-use std::{collections::HashSet, hash::Hash};
+use core::hash::Hash;
+use std::collections::HashSet;
 
 use self::traits::GeneratedTraits;
 
diff --git a/nutype_macros/src/common/gen/traits.rs b/nutype_macros/src/common/gen/traits.rs
index 1f98ba05..a2f4597e 100644
--- a/nutype_macros/src/common/gen/traits.rs
+++ b/nutype_macros/src/common/gen/traits.rs
@@ -324,8 +324,8 @@ pub fn gen_impl_trait_serde_deserialize(
         impl #all_generics_with_deserialize_bound ::serde::Deserialize<'de> for #type_name #type_generics_without_bounds {
             fn deserialize<D: ::serde::Deserializer<'de>>(deserializer: D) -> ::core::result::Result<Self, D::Error> {
                 struct __Visitor #all_generics {
-                    marker: ::std::marker::PhantomData<#type_name #type_generics_without_bounds>,
-                    lifetime: ::std::marker::PhantomData<&'de ()>,
+                    marker: ::core::marker::PhantomData<#type_name #type_generics_without_bounds>,
+                    lifetime: ::core::marker::PhantomData<&'de ()>,
                 }
 
                 impl #all_generics_with_deserialize_bound ::serde::de::Visitor<'de> for __Visitor #all_generics_without_bounds {
diff --git a/nutype_macros/src/common/models.rs b/nutype_macros/src/common/models.rs
index de57cd9b..386ec1f6 100644
--- a/nutype_macros/src/common/models.rs
+++ b/nutype_macros/src/common/models.rs
@@ -1,6 +1,6 @@
 use kinded::Kinded;
-use std::ops::Add;
-use std::{collections::HashSet, fmt::Debug};
+use core::{fmt::Debug, ops::Add};
+use std::collections::HashSet;
 use syn::Generics;
 
 use proc_macro2::{Span, TokenStream};
diff --git a/nutype_macros/src/common/parse/mod.rs b/nutype_macros/src/common/parse/mod.rs
index f207e577..d73008da 100644
--- a/nutype_macros/src/common/parse/mod.rs
+++ b/nutype_macros/src/common/parse/mod.rs
@@ -1,7 +1,7 @@
 pub mod derive_trait;
 pub mod meta;
 
-use std::{
+use core::{
     any::type_name,
     fmt::{Debug, Display},
     str::FromStr,
@@ -364,7 +364,7 @@ where
 pub fn parse_typed_custom_function<T>(
     input: ParseStream,
 ) -> syn::Result<(TypedCustomFunction, Span)> {
-    let tp_str = std::any::type_name::<T>();
+    let tp_str = core::any::type_name::<T>();
     parse_typed_custom_function_raw(input, tp_str)
 }
 
@@ -381,14 +381,14 @@ pub fn parse_typed_custom_function_raw(
 
 pub fn parse_sanitizer_kind<K>(input: ParseStream) -> syn::Result<(K, Ident)>
 where
-    K: std::str::FromStr + kinded::Kind + std::fmt::Display + 'static,
+    K: core::str::FromStr + kinded::Kind + core::fmt::Display + 'static,
 {
     parse_kind("sanitizer", input)
 }
 
 pub fn parse_validator_kind<K>(input: ParseStream) -> syn::Result<(K, Ident)>
 where
-    K: std::str::FromStr + kinded::Kind + std::fmt::Display + 'static,
+    K: core::str::FromStr + kinded::Kind + core::fmt::Display + 'static,
 {
     parse_kind("validator", input)
 }
@@ -397,7 +397,7 @@ where
 /// Build a helpful error on failure.
 fn parse_kind<K>(attr_type: &str, input: ParseStream) -> syn::Result<(K, Ident)>
 where
-    K: std::str::FromStr + kinded::Kind + std::fmt::Display + 'static,
+    K: core::str::FromStr + kinded::Kind + core::fmt::Display + 'static,
 {
     let ident: Ident = input.parse()?;
     let attr_name = ident.to_string();
diff --git a/nutype_macros/src/float/mod.rs b/nutype_macros/src/float/mod.rs
index 27b9c075..ad95f9ea 100644
--- a/nutype_macros/src/float/mod.rs
+++ b/nutype_macros/src/float/mod.rs
@@ -1,9 +1,9 @@
-use std::{
-    collections::HashSet,
+use core::{
     fmt::{Debug, Display},
     marker::PhantomData,
     str::FromStr,
 };
+use std::collections::HashSet;
 
 use proc_macro2::TokenStream;
 use quote::ToTokens;
diff --git a/nutype_macros/src/float/models.rs b/nutype_macros/src/float/models.rs
index 6fe89ae1..5ac62506 100644
--- a/nutype_macros/src/float/models.rs
+++ b/nutype_macros/src/float/models.rs
@@ -13,7 +13,7 @@ use crate::common::models::{
 #[kinded(display = "snake_case", derive(Hash))]
 pub enum FloatSanitizer<T> {
     With(TypedCustomFunction),
-    _Phantom(std::marker::PhantomData<T>),
+    _Phantom(core::marker::PhantomData<T>),
 }
 
 pub type SpannedFloatSanitizer<T> = SpannedItem<FloatSanitizer<T>>;
diff --git a/nutype_macros/src/float/parse.rs b/nutype_macros/src/float/parse.rs
index 26ec7a91..f7a22b5b 100644
--- a/nutype_macros/src/float/parse.rs
+++ b/nutype_macros/src/float/parse.rs
@@ -1,4 +1,4 @@
-use std::{
+use core::{
     fmt::{Debug, Display},
     str::FromStr,
 };
diff --git a/nutype_macros/src/integer/mod.rs b/nutype_macros/src/integer/mod.rs
index 476e0e94..8ddcd30c 100644
--- a/nutype_macros/src/integer/mod.rs
+++ b/nutype_macros/src/integer/mod.rs
@@ -1,9 +1,9 @@
-use std::{
-    collections::HashSet,
+use core::{
     fmt::{Debug, Display},
     marker::PhantomData,
     str::FromStr,
 };
+use std::collections::HashSet;
 
 use proc_macro2::TokenStream;
 use quote::ToTokens;
diff --git a/nutype_macros/src/integer/models.rs b/nutype_macros/src/integer/models.rs
index 039b3449..ec61245c 100644
--- a/nutype_macros/src/integer/models.rs
+++ b/nutype_macros/src/integer/models.rs
@@ -13,7 +13,7 @@ use crate::common::models::{
 #[kinded(display = "snake_case")]
 pub enum IntegerSanitizer<T> {
     With(TypedCustomFunction),
-    _Phantom(std::marker::PhantomData<T>),
+    _Phantom(core::marker::PhantomData<T>),
 }
 
 pub type SpannedIntegerSanitizer<T> = SpannedItem<IntegerSanitizer<T>>;
diff --git a/nutype_macros/src/integer/parse.rs b/nutype_macros/src/integer/parse.rs
index 690ec474..97eb3e4f 100644
--- a/nutype_macros/src/integer/parse.rs
+++ b/nutype_macros/src/integer/parse.rs
@@ -1,4 +1,4 @@
-use std::{
+use core::{
     fmt::{Debug, Display},
     str::FromStr,
 };


Test patch:
diff --git a/test_suite/src/test_helpers.rs b/test_suite/src/test_helpers.rs
index a8cbae43..4aef33ca 100644
--- a/test_suite/src/test_helpers.rs
+++ b/test_suite/src/test_helpers.rs
@@ -1,10 +1,10 @@
 pub mod traits {
-    pub fn should_implement_hash<T: std::hash::Hash>() {}
-    pub fn should_implement_debug<T: std::fmt::Debug>() {}
-    pub fn should_implement_from<T: std::convert::From<Inner>, Inner>() {}
-    pub fn should_implement_try_from<T: std::convert::TryFrom<Inner>, Inner>() {}
-    pub fn should_implement_from_str<T: std::str::FromStr>() {}
-    pub fn should_implement_borrow<T: std::borrow::Borrow<Borrowed>, Borrowed: ?Sized>() {}
+    pub fn should_implement_hash<T: core::hash::Hash>() {}
+    pub fn should_implement_debug<T: core::fmt::Debug>() {}
+    pub fn should_implement_from<T: core::convert::From<Inner>, Inner>() {}
+    pub fn should_implement_try_from<T: core::convert::TryFrom<Inner>, Inner>() {}
+    pub fn should_implement_from_str<T: core::str::FromStr>() {}
+    pub fn should_implement_borrow<T: core::borrow::Borrow<Borrowed>, Borrowed: ?Sized>() {}
     pub fn should_implement_clone<T: Clone>() {}
     pub fn should_implement_copy<T: Copy>() {}
     pub fn should_implement_eq<T: Eq>() {}
diff --git a/test_suite/tests/any.rs b/test_suite/tests/any.rs
index d40a718c..0faa7b43 100644
--- a/test_suite/tests/any.rs
+++ b/test_suite/tests/any.rs
@@ -1,9 +1,10 @@
 use nutype::nutype;
-use std::borrow::Cow;
-use std::cmp::{Ordering, PartialEq, PartialOrd};
+extern crate alloc;
+use alloc::borrow::Cow;
+use core::cmp::{Ordering, PartialEq, PartialOrd};
 use std::collections::{HashMap, HashSet};
-use std::fmt::Debug;
-use std::hash::Hash;
+use core::fmt::Debug;
+use core::hash::Hash;
 use test_suite::test_helpers::traits::*;
 
 // Inner custom type, which is unknown to nutype
@@ -27,13 +28,13 @@ impl Point {
     }
 }
 
-impl std::fmt::Display for Point {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl core::fmt::Display for Point {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         write!(f, "{},{}", self.x, self.y)
     }
 }
 
-impl std::str::FromStr for Point {
+impl core::str::FromStr for Point {
     type Err = &'static str;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -96,7 +97,7 @@ mod traits {
 
     #[test]
     fn test_partial_ord() {
-        use std::cmp::Ordering;
+        use core::cmp::Ordering;
 
         let loc1 = Location::new(Point::new(1, 1));
         let loc2 = Location::new(Point::new(1, 2));
@@ -108,7 +109,7 @@ mod traits {
 
     #[test]
     fn test_ord() {
-        use std::cmp::Ordering;
+        use core::cmp::Ordering;
 
         let loc1 = Location::new(Point::new(1, 1));
         let loc2 = Location::new(Point::new(1, 2));
@@ -163,7 +164,7 @@ mod traits {
 
     #[test]
     fn test_borrow() {
-        use std::borrow::Borrow;
+        use core::borrow::Borrow;
 
         let location = Location::from(Point::new(3, 4));
         let point: &Point = location.borrow();
@@ -592,8 +593,8 @@ mod with_generics {
         }
 
         {
-            let nan1 = WrapperPartialOrd::new(std::f64::NAN);
-            let nan2 = WrapperPartialOrd::new(std::f64::NAN);
+            let nan1 = WrapperPartialOrd::new(f64::NAN);
+            let nan2 = WrapperPartialOrd::new(f64::NAN);
             assert_eq!(nan1.partial_cmp(&nan2), None);
         }
     }
@@ -882,7 +883,7 @@ mod with_generics {
 
     #[test]
     fn test_derive_borrow_with_generic_boundaries_and_validation_and_sanitization() {
-        use std::borrow::Borrow;
+        use core::borrow::Borrow;
 
         #[nutype(
             sanitize(with = |mut v| { v.sort(); v }),
diff --git a/test_suite/tests/float.rs b/test_suite/tests/float.rs
index b9724619..051b726b 100644
--- a/test_suite/tests/float.rs
+++ b/test_suite/tests/float.rs
@@ -433,7 +433,7 @@ mod traits {
 
     #[test]
     fn test_trait_borrow() {
-        use std::borrow::Borrow;
+        use core::borrow::Borrow;
 
         #[nutype(derive(Borrow))]
         pub struct Age(f64);
@@ -517,7 +517,7 @@ mod traits {
     #[cfg(test)]
     mod tests {
         use super::*;
-        use std::cmp::Ordering;
+        use core::cmp::Ordering;
 
         #[test]
         fn test_trait_ord_f32() {
diff --git a/test_suite/tests/integer.rs b/test_suite/tests/integer.rs
index eea1c597..aaf1d404 100644
--- a/test_suite/tests/integer.rs
+++ b/test_suite/tests/integer.rs
@@ -608,7 +608,7 @@ mod traits {
 
     #[test]
     fn test_trait_borrow() {
-        use std::borrow::Borrow;
+        use core::borrow::Borrow;
 
         #[nutype(derive(Borrow))]
         pub struct Age(u8);
diff --git a/test_suite/tests/string.rs b/test_suite/tests/string.rs
index d2014077..874c808d 100644
--- a/test_suite/tests/string.rs
+++ b/test_suite/tests/string.rs
@@ -213,7 +213,7 @@ mod validators {
 
     #[test]
     fn test_error() {
-        fn ensure_type_implements_error<T: std::error::Error>() {}
+        fn ensure_type_implements_error<T: core::error::Error>() {}
 
         #[nutype(validate(not_empty), derive(Debug, PartialEq))]
         pub struct Email(String);
@@ -391,7 +391,7 @@ mod derives {
 
     #[test]
     fn test_trait_borrow_str() {
-        use std::borrow::Borrow;
+        use core::borrow::Borrow;
 
         #[nutype(derive(Borrow))]
         pub struct Name(String);
@@ -403,7 +403,7 @@ mod derives {
 
     #[test]
     fn test_trait_borrow_string() {
-        use std::borrow::Borrow;
+        use core::borrow::Borrow;
 
         #[nutype(derive(Borrow))]
         pub struct Name(String);