Skip to content

Commit

Permalink
Merge pull request #122 from greyblake/no-std-support
Browse files Browse the repository at this point in the history
Support no_std
  • Loading branch information
greyblake committed Jan 28, 2024
2 parents 1bc35f9 + 5b259e4 commit f900391
Show file tree
Hide file tree
Showing 15 changed files with 280 additions and 18 deletions.
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

0 comments on commit f900391

Please sign in to comment.