Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support no_std #122

Merged
merged 3 commits into from
Jan 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,20 @@ jobs:
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: thumbv7m-none-eabi # Needed for no_std_example

- name: Run examples
run: |
for example in $(ls ./examples/); do
cargo run --bin $example
set -euxo pipefail
ROOT_DIR=$(pwd)
for EXAMPLE in `ls examples`; do
cd $ROOT_DIR/examples/$EXAMPLE;
if [[ "$EXAMPLE" == "no_std_example" ]]
then
cargo build
else
cargo run
fi
done

typos:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### v0.4.1 - xxxx-xx-xx

* Support `no_std` ( the dependency needs to be declared as `nutype = { default-features = false }` )
* Support integration with [`arbitrary`](https://crates.io/crates/arbitrary) crate (see `arbitrary` feature).
* Support `Arbitrary` for integer types
* Support `Arbitrary` for float types
Expand Down
13 changes: 12 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,16 @@ members = [
"nutype_macros",
"test_suite",
"dummy",
"examples/*",

# All examples except "no_std_example" are tested in the test suite
"examples/any_arbitrary",
"examples/float_arbitrary",
"examples/float_sortable",
"examples/integer_arbitrary",
"examples/integer_bounded",
"examples/new_unchecked_example",
# "examples/no_std_example",
"examples/serde_complex",
"examples/string_bounded_len",
"examples/string_regex_email",
]
13 changes: 12 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,18 @@ clippy:
cargo clippy -- -D warnings

examples:
for example in `ls examples`; do cargo run --bin $example; done
#!/usr/bin/env bash
set -euxo pipefail
ROOT_DIR=$(pwd)
for EXAMPLE in `ls examples`; do
cd $ROOT_DIR/examples/$EXAMPLE;
if [[ "$EXAMPLE" == "no_std_example" ]]
then
cargo build
else
cargo run
fi
done

typos:
which typos >/dev/null || cargo install typos-cli
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,10 +354,12 @@ assert_eq!(name.into_inner(), " boo ");

## Feature flags

* `serde` - integrations with [`serde`](https://crates.io/crates/serde) crate. Allows to derive `Serialize` and `Deserialize` traits.
* `arbitrary` - enables derive of [`arbitrary::Arbitrary`](https://docs.rs/arbitrary/latest/arbitrary/trait.Arbitrary.html).
* `new_unchecked` - enables generation of unsafe `::new_unchecked()` function.
* `regex` - allows to use `regex = ` validation on string-based types. Note: your crate also has to explicitly have `regex` and `lazy_static` within dependencies.
* `serde` - integrations with [`serde`](https://crates.io/crates/serde) crate. Allows to derive `Serialize` and `Deserialize` traits.
* `schemars08` - allows to derive [`JsonSchema`](https://docs.rs/schemars/0.8.12/schemars/trait.JsonSchema.html) trait of [schemars](https://crates.io/crates/schemars) crate. Note that at the moment validation rules are not respected.
* `new_unchecked` - enables generation of unsafe `::new_unchecked()` function.
* `std` - enabled by default. Use `default-features = false` to disable.

## When nutype is a good fit for you?

Expand Down
2 changes: 2 additions & 0 deletions examples/no_std_example/.cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build]
target = "thumbv7m-none-eabi"
112 changes: 112 additions & 0 deletions examples/no_std_example/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions examples/no_std_example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "no_std_example"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
nutype = { path = "../../nutype", default-features = false }

# Exclude this package from the common workspace, since it's no_std.
[workspace]
74 changes: 74 additions & 0 deletions examples/no_std_example/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// This example exists to ensure that code generated by nutype macro
// can compile in no_std environment.
#![no_main]
#![no_std]

use core::panic::PanicInfo;
use nutype::nutype;

#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
loop {}
}

// Integer
#[nutype(
validate(greater_or_equal = 1, less_or_equal = 6),
sanitize(with = |x| x),
derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
FromStr,
AsRef,
Deref,
TryFrom,
Into,
Hash,
Borrow,
Display,
Default,
),
default = 4
)]
struct GermanTaxClass(i64);

// Float
#[nutype(
validate(greater_or_equal = 0.0, less_or_equal = 1024.0, finite),
sanitize(with = |x| x),
derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
FromStr,
AsRef,
Deref,
TryFrom,
Into,
Borrow,
Display,
Default,
),
default = 0.0
)]
struct Width(f64);

// NOTE: strings are not working yet with no_std

// Any other type
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Point {
x: i32,
y: i32,
}
#[nutype(derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsRef, Into, From, Deref, Borrow, Hash
))]
pub struct Location(Point);
3 changes: 3 additions & 0 deletions nutype/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ categories = ["data-structures", "rust-patterns"]
nutype_macros = { version = "0.4.0", path = "../nutype_macros" }

[features]
default = ["std"]

std = ["nutype_macros/std"]
serde = ["nutype_macros/serde"]
regex = ["nutype_macros/regex"]
schemars08 = ["nutype_macros/schemars08"]
Expand Down
9 changes: 7 additions & 2 deletions nutype/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,12 @@
//!
//! ## Feature flags
//!
//! * `serde` - integrations with [`serde`](https://crates.io/crates/serde) crate. Allows to derive `Serialize` and `Deserialize` traits.
//! * `arbitrary` - enables derive of [`arbitrary::Arbitrary`](https://docs.rs/arbitrary/latest/arbitrary/trait.Arbitrary.html).
//! * `new_unchecked` - enables generation of unsafe `::new_unchecked()` function.
//! * `schemars08` - allows to derive [`JsonSchema`](https://docs.rs/schemars/0.8.12/schemars/trait.JsonSchema.html) trait of [schemars](https://crates.io/crates/schemars) crate. Note that at the moment validation rules are not respected.
//! * `regex` - allows to use `regex = ` validation on string-based types. Note: your crate also has to explicitly have `regex` and `lazy_static` within dependencies.
//! * `serde` - integrations with [`serde`](https://crates.io/crates/serde) crate. Allows to derive `Serialize` and `Deserialize` traits.
//! * `schemars08` - allows to derive [`JsonSchema`](https://docs.rs/schemars/0.8.12/schemars/trait.JsonSchema.html) trait of [schemars](https://crates.io/crates/schemars) crate. Note that at the moment validation rules are not respected.
//! * `std` - enabled by default. Use `default-features = false` to disable.
//!
//! ## Support Ukrainian military forces 🇺🇦
//!
Expand All @@ -404,6 +406,9 @@
//!
//! Thank you.

// Set `no_std` flag if `std` feature is disabled.
#![cfg_attr(not(feature = "std"), no_std)]

pub use nutype_macros::nutype;

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions nutype_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ urlencoding = "2.0"
proc-macro = true

[features]
std = []
serde = []
schemars08 = []
new_unchecked = []
Expand Down
18 changes: 14 additions & 4 deletions nutype_macros/src/common/gen/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cfg_if::cfg_if;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

Expand All @@ -8,12 +9,21 @@ pub fn gen_error_type_name(type_name: &TypeName) -> ErrorTypeName {
ErrorTypeName::new(ident)
}

// NOTE: There is no `::core::error::Error` yet in stable Rust.
// So for `no_std` we just don't implement `Error` trait.
#[allow(unused_variables)]
pub fn gen_impl_error_trait(error_type_name: &ErrorTypeName) -> TokenStream {
quote! {
impl ::std::error::Error for #error_type_name {
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
None
cfg_if! {
if #[cfg(feature = "std")] {
quote! {
impl ::std::error::Error for #error_type_name {
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
None
}
}
}
} else {
quote!{}
}
}
}
19 changes: 14 additions & 5 deletions nutype_macros/src/common/gen/parse_error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cfg_if::cfg_if;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

Expand Down Expand Up @@ -55,11 +56,19 @@ pub fn gen_def_parse_error(
}
};

let impl_std_error = quote! {
impl ::std::error::Error for #parse_error_type_name {
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
None
}
cfg_if! {
if #[cfg(feature = "std")] {
let impl_std_error = quote! {
impl ::std::error::Error for #parse_error_type_name {
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
None
}
}
};
} else {
// NOTE: There is no `::core::error::Error` yet in stable Rust.
// So for `no_std` we just don't implement `Error` trait.
let impl_std_error = quote! {};
}
};

Expand Down
2 changes: 1 addition & 1 deletion nutype_macros/src/float/gen/traits/arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ fn generate_float_with_condition(
for i in 0..1000 {
// With every iteration we modify next single byte by adding `i` value to
// it.
let index = i % std::mem::size_of::<#inner_type>();
let index = i % core::mem::size_of::<#inner_type>();
bytes[index] = bytes[index].wrapping_add((i % 256) as u8);

// Try to convert the bytes back to float in both BE and NE formats and see
Expand Down
Loading