From eef47fa6c85da0450143694cae75ecc4423ac752 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sat, 14 Dec 2024 18:54:34 -0700 Subject: [PATCH 1/3] Add `no_std` use by weakening crate requirements to `alloc` `std` is now a default-enabled feature, and it is also implied by `arbitrary`. --- Cargo.toml | 8 +++++--- src/lib.rs | 47 +++++++++++++++++++++++++++++++++++------------ src/nonzero.rs | 12 ++++++------ 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1864b23..7aa0752 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,16 +3,18 @@ name = "nonempty" version = "0.10.0" description = "Correct by construction non-empty vector" authors = ["Alexis Sellier "] -edition = "2018" +edition = "2021" license = "MIT" repository = "https://github.com/cloudhead/nonempty" [dependencies] -serde = { features = ["serde_derive"], optional = true, version = "1" } +serde = { features = ["derive", "alloc"], default-features = false, optional = true, version = "1" } arbitrary = { features = ["derive"], optional = true, version = "1" } [features] -serialize = ["serde"] +default = ["std"] +std = [] +serialize = ["dep:serde"] arbitrary = ["dep:arbitrary"] [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 6db4b07..f8b8b89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,8 @@ //! The simplest way to construct a [`NonEmpty`] is via the [`nonempty`] macro: //! //! ``` +//! # extern crate alloc; +//! # use alloc::vec::Vec; //! use nonempty::{NonEmpty, nonempty}; //! //! let l: NonEmpty = nonempty![1, 2, 3]; @@ -28,6 +30,8 @@ //! Unlike the familiar `vec!` macro, `nonempty!` requires at least one element: //! //! ``` +//! # extern crate alloc; +//! # use alloc::vec::Vec; //! use nonempty::nonempty; //! //! let l = nonempty![1]; @@ -40,6 +44,8 @@ //! [`NonEmpty::new`] or its constructor: //! //! ``` +//! # extern crate alloc; +//! # use alloc::vec::Vec; //! use nonempty::NonEmpty; //! //! let mut l = NonEmpty { head: 42, tail: vec![36, 58] }; @@ -67,7 +73,9 @@ //! Since `NonEmpty` must have a least one element, it is not possible to //! implement the `FromIterator` trait for it. We can't know, in general, if //! any given `Iterator` actually contains something. -//! + +#![no_std] + //! # Features //! //! * `serialize`: `serde` support. @@ -79,9 +87,17 @@ use serde::{ ser::{SerializeSeq, Serializer}, Deserialize, Serialize, }; -use std::mem; -use std::{cmp::Ordering, num::NonZeroUsize}; -use std::{iter, vec}; + +use core::iter; +use core::mem; +use core::{cmp::Ordering, num::NonZeroUsize}; + +#[cfg(feature = "std")] +extern crate std; + +#[cfg_attr(test, macro_use)] +extern crate alloc; +use alloc::vec::{self, Vec}; pub mod nonzero; @@ -89,6 +105,8 @@ pub mod nonzero; /// for constructing [`NonEmpty`] values. /// /// ``` +/// # extern crate alloc; +/// # use alloc::vec::Vec; /// use nonempty::{NonEmpty, nonempty}; /// /// let v = nonempty![1, 2, 3]; @@ -113,7 +131,7 @@ macro_rules! nonempty { ($h:expr) => { $crate::NonEmpty { head: $h, - tail: Vec::new(), + tail: alloc::vec::Vec::new(), } }; } @@ -984,14 +1002,14 @@ impl IntoIterator for NonEmpty { impl<'a, T> IntoIterator for &'a NonEmpty { type Item = &'a T; - type IntoIter = iter::Chain, std::slice::Iter<'a, T>>; + type IntoIter = iter::Chain, core::slice::Iter<'a, T>>; fn into_iter(self) -> Self::IntoIter { iter::once(&self.head).chain(self.tail.iter()) } } -impl std::ops::Index for NonEmpty { +impl core::ops::Index for NonEmpty { type Output = T; /// ``` @@ -1012,7 +1030,7 @@ impl std::ops::Index for NonEmpty { } } -impl std::ops::IndexMut for NonEmpty { +impl core::ops::IndexMut for NonEmpty { fn index_mut(&mut self, index: usize) -> &mut T { if index > 0 { &mut self.tail[index - 1] @@ -1030,7 +1048,9 @@ impl Extend for NonEmpty { #[cfg(feature = "serialize")] pub mod serialize { - use std::{convert::TryFrom, fmt}; + use core::{convert::TryFrom, fmt}; + + use alloc::vec::Vec; use super::NonEmpty; @@ -1060,6 +1080,8 @@ pub mod serialize { #[cfg(test)] mod tests { + use alloc::{string::String, vec::Vec}; + use crate::NonEmpty; #[test] @@ -1128,7 +1150,7 @@ mod tests { #[test] fn test_to_nonempty() { - use std::iter::{empty, once}; + use core::iter::{empty, once}; assert_eq!(NonEmpty::<()>::collect(empty()), None); assert_eq!(NonEmpty::<()>::collect(once(())), Some(NonEmpty::new(()))); @@ -1196,13 +1218,14 @@ mod tests { #[cfg(feature = "serialize")] mod serialize { use crate::NonEmpty; + use alloc::boxed::Box; use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct SimpleSerializable(pub i32); #[test] - fn test_simple_round_trip() -> Result<(), Box> { + fn test_simple_round_trip() -> Result<(), Box> { // Given let mut non_empty = NonEmpty::new(SimpleSerializable(42)); non_empty.push(SimpleSerializable(777)); @@ -1219,7 +1242,7 @@ mod tests { } #[test] - fn test_serialization() -> Result<(), Box> { + fn test_serialization() -> Result<(), Box> { let ne = nonempty![1, 2, 3, 4, 5]; let ve = vec![1, 2, 3, 4, 5]; diff --git a/src/nonzero.rs b/src/nonzero.rs index 4d61102..243eb4c 100644 --- a/src/nonzero.rs +++ b/src/nonzero.rs @@ -1,9 +1,9 @@ #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; -use std::num::NonZeroUsize; +use core::num::NonZeroUsize; /// A non-empty list which statically guarantees certain operations -/// cannot return zero, using [`std::num::NonZeroUsize`]. +/// cannot return zero, using [`core::num::NonZeroUsize`]. /// /// *Experimental* /// @@ -35,7 +35,7 @@ impl From> for NonEmpty { } } -impl std::ops::Deref for NonEmpty { +impl core::ops::Deref for NonEmpty { type Target = super::NonEmpty; fn deref(&self) -> &Self::Target { @@ -43,7 +43,7 @@ impl std::ops::Deref for NonEmpty { } } -impl std::ops::DerefMut for NonEmpty { +impl core::ops::DerefMut for NonEmpty { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } @@ -54,7 +54,7 @@ mod tests { use crate::nonzero; use crate::NonEmpty; - use std::convert::TryInto; + use core::convert::TryInto; #[test] fn test_nonzero() { @@ -69,7 +69,7 @@ mod tests { use crate::nonzero; use arbitrary::{Arbitrary, Unstructured}; - use std::convert::TryInto; + use core::convert::TryInto; #[test] fn test_nonzero_arbitrary_empty_tail() -> arbitrary::Result<()> { From 97b894473836072b08687fb8b20825e9ff2aa72a Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sat, 14 Dec 2024 18:57:52 -0700 Subject: [PATCH 2/3] Add a CHANGELOG --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..036b0d6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog +All notable changes to this library will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this library adheres to Rust's notion of +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added +- `std` feature flag; building with `--no-default-features` now enables `no_std` use. + +### Changed +- MSRV is now 1.56 (this is a semver-breaking change) From edcdf26e7ed6cdb7f29a0e70fea45b383597ff61 Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Tue, 17 Dec 2024 12:01:12 +0000 Subject: [PATCH 3/3] github: add run step for no-std Signed-off-by: Fintan Halpenny X-Clacks-Overhead: GNU Terry Pratchett --- .github/workflows/actions.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 17d2faa..e752843 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -21,6 +21,20 @@ jobs: RUSTFLAGS: -D warnings - name: Run tests run: cargo test --all --verbose --features serialize,arbitrary + no-std: + name: no-std build and test + strategy: + matrix: + os: ['ubuntu-latest', 'macos-latest'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - name: Build + run: cargo build --verbose --no-default-features + env: + RUSTFLAGS: -D warnings + - name: Run tests + run: cargo test --all --verbose --no-default-features rustfmt_and_clippy: name: Check rustfmt style && run clippy