Skip to content

Commit

Permalink
rework #![no_std] support, switch on alloc (#236)
Browse files Browse the repository at this point in the history
* rework #![no_std] support, switch on `alloc`

Most of the uses of `std` in the crate are of `Vec`, `String`, and
`Box`, which are in `alloc`, which is available on `#![no_std]`
platforms via `extern crate alloc;`. This commit adjusts these uses to
use `alloc` directly and adds an `"alloc"` feature flag to control them.
The notable exceptions still requiring a `std` flag are `HashMap` and
`HashSet` (I'm working on a separate change to add `BTree{Map,Set}`
support for `#![no_std]` envs). `frunk_core` no longer needs a `std`
flag: it has been removed.

The reimport of `core` as `std` (see #220 for historical explanation) is
converted to direct usage of `core` everywhere.

Removed `#[cfg(feature = "std")]` condition from `frunk_laws` and made
it depend on `frunk/std` -- it depends on `quickcheck`, which requires
`std`.

Added `#[cfg(test)] extern crate std;` to `#![no_std]` crates, as `std`
is required to run the libtest harness.

Tested working against all the combinations of feature flags I could
think of.

* bump minor version, unremove frunk_core/std and mark deprecated

* fix rustfmt
  • Loading branch information
mammothbane authored Aug 31, 2024
1 parent 1ca9c99 commit 93c4db7
Show file tree
Hide file tree
Showing 15 changed files with 91 additions and 65 deletions.
13 changes: 9 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "frunk"
edition = "2021"
version = "0.4.2"
version = "0.4.3"
authors = ["Lloyd <[email protected]>"]
description = "Frunk provides developers with a number of functional programming tools like HList, Coproduct, Generic, LabelledGeneric, Validated, Monoid, Semigroup and friends."
license = "MIT"
Expand Down Expand Up @@ -41,10 +41,15 @@ version = "0.5.0"
serde = { version = "^1.0", optional = true, features = [ "derive" ] }

[features]
default = ["validated", "proc-macros"]
validated = ["std"]
default = ["validated", "proc-macros", "alloc"]
validated = ["alloc"]
proc-macros = ["frunk_proc_macros"]
std = ["frunk_core/std"]
std = ["alloc", "serde?/std"]
alloc = ["frunk_core/alloc", "serde?/alloc"]

[[example]]
name = "paths"
required-features = ["proc-macros"]

[profile.bench]
opt-level = 3
Expand Down
9 changes: 6 additions & 3 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "frunk_core"
edition = "2021"
version = "0.4.2"
version = "0.4.3"
authors = ["Lloyd <[email protected]>"]
description = "Frunk core provides developers with HList, Coproduct, LabelledGeneric and Generic"
license = "MIT"
Expand All @@ -13,8 +13,11 @@ keywords = ["Frunk", "HList", "Generic", "Coproduct", "LabelledGeneric"]
travis-ci = { repository = "lloydmeta/frunk" }

[features]
default = ["std"]
std = []
default = ["alloc"]
alloc = ["serde?/alloc"]

# deprecated -- to be removed in next major version
std = ["alloc"]

[dependencies]
serde = { version = "^1.0", optional = true, features = [ "derive" ] }
Expand Down
5 changes: 3 additions & 2 deletions core/src/coproduct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,9 @@ mod tests {
use super::Coproduct::*;
use super::*;

use std::format;
use std::string::{String, ToString};

#[test]
fn test_coproduct_inject() {
type I32StrBool = Coprod!(i32, &'static str, bool);
Expand All @@ -1267,7 +1270,6 @@ mod tests {
}

#[test]
#[cfg(feature = "std")]
fn test_coproduct_fold_consuming() {
type I32F32StrBool = Coprod!(i32, f32, bool);

Expand Down Expand Up @@ -1312,7 +1314,6 @@ mod tests {
}

#[test]
#[cfg(feature = "std")]
fn test_coproduct_fold_non_consuming() {
type I32F32Bool = Coprod!(i32, f32, bool);

Expand Down
15 changes: 9 additions & 6 deletions core/src/hlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@

use crate::indices::{Here, Suffixed, There};
use crate::traits::{Func, IntoReverse, Poly, ToMut, ToRef};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use std::ops::Add;
use core::ops::Add;

/// Typeclass for HList-y behaviour
///
Expand Down Expand Up @@ -432,7 +434,7 @@ macro_rules! gen_inherent_methods {
/// # }
/// ```
#[inline(always)]
pub fn map<F>(self,mapper: F) -> <Self as HMappable<F>>::Output
pub fn map<F>(self, mapper: F) -> <Self as HMappable<F>>::Output
where Self: HMappable<F>,
{
HMappable::map(self, mapper)
Expand Down Expand Up @@ -1433,7 +1435,7 @@ where
}
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
#[allow(clippy::from_over_into)]
impl<H, Tail> Into<Vec<H>> for HCons<H, Tail>
where
Expand All @@ -1450,7 +1452,7 @@ where
}
}

#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
#[allow(clippy::from_over_into)]
impl<T> Into<Vec<T>> for HNil {
fn into(self) -> Vec<T> {
Expand Down Expand Up @@ -1577,6 +1579,8 @@ where
mod tests {
use super::*;

use alloc::vec;

#[test]
fn test_hcons() {
let hlist1 = h_cons(1, HNil);
Expand Down Expand Up @@ -1909,7 +1913,6 @@ mod tests {
}

#[test]
#[cfg(feature = "std")]
fn test_single_func_foldl_consuming() {
use std::collections::HashMap;

Expand Down Expand Up @@ -1949,7 +1952,7 @@ mod tests {
}

#[test]
#[cfg(feature = "std")]
#[cfg(feature = "alloc")]
fn test_into_vec() {
let h = hlist![1, 2, 3, 4, 5];
let as_vec: Vec<_> = h.into();
Expand Down
2 changes: 1 addition & 1 deletion core/src/indices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//!
//! **...yet.** `;)`

use std::marker::PhantomData;
use core::marker::PhantomData;

// Largely lifted from https://github.com/Sgeo/hlist/blob/master/src/lib.rs#L30

Expand Down
15 changes: 9 additions & 6 deletions core/src/labelled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ use crate::indices::*;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use ::std::fmt;
use ::std::marker::PhantomData;
use core::fmt;
use core::marker::PhantomData;

/// A trait that converts from a type to a labelled generic representation.
///
Expand Down Expand Up @@ -733,11 +733,13 @@ impl<Key, SourceValue> Transmogrifier<SourceValue, IdentityTransMog> for Field<K
}

/// Implementations of `Transmogrifier` that allow recursion through stdlib container types.
#[cfg(feature = "std")]
mod std {
#[cfg(feature = "alloc")]
mod _alloc {
use super::MappingIndicesWrapper;
use super::{Field, Transmogrifier};
use std::collections::{LinkedList, VecDeque};
use alloc::boxed::Box;
use alloc::collections::{LinkedList, VecDeque};
use alloc::vec::Vec;

macro_rules! transmogrify_seq {
($container:ident) => {
Expand Down Expand Up @@ -914,7 +916,8 @@ where
mod tests {
use super::chars::*;
use super::*;
use ::std::collections::{LinkedList, VecDeque};
use alloc::collections::{LinkedList, VecDeque};
use alloc::{boxed::Box, format, vec, vec::Vec};

// Set up some aliases
#[allow(non_camel_case_types)]
Expand Down
9 changes: 6 additions & 3 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]
#![doc(html_playground_url = "https://play.rust-lang.org/")]
//! Frunk Core
//!
Expand Down Expand Up @@ -58,8 +58,11 @@
//! 1. [Source on Github](https://github.com/lloydmeta/frunk)
//! 2. [Crates.io page](https://crates.io/crates/frunk)

#[cfg(not(feature = "std"))]
extern crate core as std;
#[cfg(test)]
extern crate std;

#[cfg(feature = "alloc")]
extern crate alloc;

#[macro_use]
mod macros;
Expand Down
4 changes: 2 additions & 2 deletions core/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@
use super::hlist::*;
use super::labelled::*;

use std::marker::PhantomData;
use std::ops::Add;
use core::marker::PhantomData;
use core::ops::Add;

#[derive(Clone, Copy, Debug)]
pub struct Path<T>(PhantomData<T>);
Expand Down
3 changes: 2 additions & 1 deletion laws/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "frunk_laws"
edition = "2021"
version = "0.5.0"
version = "0.5.1"
authors = ["Lloyd <[email protected]>"]
description = "frunk_laws contains laws for algebras declared in Frunk."
license = "MIT"
Expand All @@ -16,6 +16,7 @@ travis-ci = { repository = "lloydmeta/frunk" }
path = ".."
default-features = false
version = "0.4.2"
features = ["std"]

[dependencies]
quickcheck = "1.0.3"
6 changes: 0 additions & 6 deletions laws/src/monoid_laws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,39 +66,33 @@ mod tests {
use crate::wrapper::*;
use frunk::semigroup::*;
use quickcheck::quickcheck;
#[cfg(feature = "std")]
use std::collections::{HashMap, HashSet};

#[test]
#[cfg(feature = "std")]
fn string_id_prop() {
quickcheck(left_identity as fn(String) -> bool);
quickcheck(right_identity as fn(String) -> bool);
}

#[test]
#[cfg(feature = "std")]
fn option_id_prop() {
quickcheck(left_identity as fn(Option<String>) -> bool);
quickcheck(right_identity as fn(Option<String>) -> bool);
}

#[test]
#[cfg(feature = "std")]
fn vec_id_prop() {
quickcheck(left_identity as fn(Vec<String>) -> bool);
quickcheck(right_identity as fn(Vec<String>) -> bool);
}

#[test]
#[cfg(feature = "std")]
fn hashset_id_prop() {
quickcheck(left_identity as fn(HashSet<i32>) -> bool);
quickcheck(right_identity as fn(HashSet<i32>) -> bool);
}

#[test]
#[cfg(feature = "std")]
fn hashmap_id_prop() {
quickcheck(left_identity as fn(HashMap<i32, String>) -> bool);
quickcheck(right_identity as fn(HashMap<i32, String>) -> bool);
Expand Down
6 changes: 0 additions & 6 deletions laws/src/semigroup_laws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,35 +42,29 @@ mod tests {
use super::*;
use crate::wrapper::*;
use quickcheck::quickcheck;
#[cfg(feature = "std")]
use std::collections::{HashMap, HashSet};

#[test]
#[cfg(feature = "std")]
fn string_prop() {
quickcheck(associativity as fn(String, String, String) -> bool)
}

#[test]
#[cfg(feature = "std")]
fn option_prop() {
quickcheck(associativity as fn(Option<String>, Option<String>, Option<String>) -> bool)
}

#[test]
#[cfg(feature = "std")]
fn vec_prop() {
quickcheck(associativity as fn(Vec<i8>, Vec<i8>, Vec<i8>) -> bool)
}

#[test]
#[cfg(feature = "std")]
fn hashset_prop() {
quickcheck(associativity as fn(HashSet<i8>, HashSet<i8>, HashSet<i8>) -> bool)
}

#[test]
#[cfg(feature = "std")]
fn hashmap_prop() {
quickcheck(
associativity
Expand Down
11 changes: 7 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]
#![doc(html_playground_url = "https://play.rust-lang.org/")]
//! Frunk: generic functional programming toolbelt for Rust
//!
Expand All @@ -13,7 +13,7 @@
//! 6. Monoid
//!
#![cfg_attr(
feature = "std",
feature = "alloc",
doc = r#"
Here is a small taste of what Frunk has to offer:
Expand Down Expand Up @@ -201,8 +201,11 @@ assert_eq!(d_user.first_name, "Joe");
//! 1. [Source on Github](https://github.com/lloydmeta/frunk)
//! 2. [Crates.io page](https://crates.io/crates/frunk)

#[cfg(not(feature = "std"))]
extern crate core as std;
#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(any(feature = "std", test))]
extern crate std;

pub mod monoid;
pub mod semigroup;
Expand Down
Loading

1 comment on commit 93c4db7

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Frunk Benchmarks'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: 93c4db7 Previous: 1ca9c99 Ratio
empty 0.31 ns/iter (± 0.00) 0 ns/iter (± 0) +∞
generic_conversion 0.77 ns/iter (± 0.01) 0 ns/iter (± 0) +∞
hlist_into_hlist_pat_match 0.77 ns/iter (± 0.13) 0 ns/iter (± 0) +∞
hlist_into_tuple2_match 0.77 ns/iter (± 0.01) 0 ns/iter (± 0) +∞
labelled_conversion 0.77 ns/iter (± 0.67) 0 ns/iter (± 0) +∞
name 0.31 ns/iter (± 0.00) 0 ns/iter (± 0) +∞
sculpted_conversion 0.77 ns/iter (± 0.01) 0 ns/iter (± 0) +∞
lens_path_read_mut 0.31 ns/iter (± 0.01) 0 ns/iter (± 0) +∞
lens_path_read_ref 0.31 ns/iter (± 0.01) 0 ns/iter (± 0) +∞
lens_path_read_value 0.31 ns/iter (± 0.00) 0 ns/iter (± 0) +∞
normal_path_read_mut 0.31 ns/iter (± 0.00) 0 ns/iter (± 0) +∞
normal_path_read_ref 0.31 ns/iter (± 0.00) 0 ns/iter (± 0) +∞
normal_path_read_value 0.31 ns/iter (± 0.00) 0 ns/iter (± 0) +∞
std_add_i32 0.31 ns/iter (± 0.00) 0 ns/iter (± 0) +∞

This comment was automatically generated by workflow using github-action-benchmark.

CC: @lloydmeta

Please sign in to comment.