Skip to content
Closed
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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)
8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ name = "nonempty"
version = "0.10.0"
description = "Correct by construction non-empty vector"
authors = ["Alexis Sellier <self@cloudhead.io>"]
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]
Expand Down
47 changes: 35 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u32> = nonempty![1, 2, 3];
Expand All @@ -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];
Expand All @@ -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] };
Expand Down Expand Up @@ -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.
Expand All @@ -79,16 +87,26 @@ 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;

/// Like the `vec!` macro, but enforces at least one argument. A nice short-hand
/// for constructing [`NonEmpty`] values.
///
/// ```
/// # extern crate alloc;
/// # use alloc::vec::Vec;
/// use nonempty::{NonEmpty, nonempty};
///
/// let v = nonempty![1, 2, 3];
Expand All @@ -113,7 +131,7 @@ macro_rules! nonempty {
($h:expr) => {
$crate::NonEmpty {
head: $h,
tail: Vec::new(),
tail: alloc::vec::Vec::new(),
}
};
}
Expand Down Expand Up @@ -984,14 +1002,14 @@ impl<T> IntoIterator for NonEmpty<T> {

impl<'a, T> IntoIterator for &'a NonEmpty<T> {
type Item = &'a T;
type IntoIter = iter::Chain<iter::Once<&'a T>, std::slice::Iter<'a, T>>;
type IntoIter = iter::Chain<iter::Once<&'a T>, core::slice::Iter<'a, T>>;

fn into_iter(self) -> Self::IntoIter {
iter::once(&self.head).chain(self.tail.iter())
}
}

impl<T> std::ops::Index<usize> for NonEmpty<T> {
impl<T> core::ops::Index<usize> for NonEmpty<T> {
type Output = T;

/// ```
Expand All @@ -1012,7 +1030,7 @@ impl<T> std::ops::Index<usize> for NonEmpty<T> {
}
}

impl<T> std::ops::IndexMut<usize> for NonEmpty<T> {
impl<T> core::ops::IndexMut<usize> for NonEmpty<T> {
fn index_mut(&mut self, index: usize) -> &mut T {
if index > 0 {
&mut self.tail[index - 1]
Expand All @@ -1030,7 +1048,9 @@ impl<A> Extend<A> for NonEmpty<A> {

#[cfg(feature = "serialize")]
pub mod serialize {
use std::{convert::TryFrom, fmt};
use core::{convert::TryFrom, fmt};

use alloc::vec::Vec;

use super::NonEmpty;

Expand Down Expand Up @@ -1060,6 +1080,8 @@ pub mod serialize {

#[cfg(test)]
mod tests {
use alloc::{string::String, vec::Vec};

use crate::NonEmpty;

#[test]
Expand Down Expand Up @@ -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(())));
Expand Down Expand Up @@ -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<dyn std::error::Error>> {
fn test_simple_round_trip() -> Result<(), Box<dyn core::error::Error>> {
// Given
let mut non_empty = NonEmpty::new(SimpleSerializable(42));
non_empty.push(SimpleSerializable(777));
Expand All @@ -1219,7 +1242,7 @@ mod tests {
}

#[test]
fn test_serialization() -> Result<(), Box<dyn std::error::Error>> {
fn test_serialization() -> Result<(), Box<dyn core::error::Error>> {
let ne = nonempty![1, 2, 3, 4, 5];
let ve = vec![1, 2, 3, 4, 5];

Expand Down
12 changes: 6 additions & 6 deletions src/nonzero.rs
Original file line number Diff line number Diff line change
@@ -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*
///
Expand Down Expand Up @@ -35,15 +35,15 @@ impl<T> From<super::NonEmpty<T>> for NonEmpty<T> {
}
}

impl<T> std::ops::Deref for NonEmpty<T> {
impl<T> core::ops::Deref for NonEmpty<T> {
type Target = super::NonEmpty<T>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<T> std::ops::DerefMut for NonEmpty<T> {
impl<T> core::ops::DerefMut for NonEmpty<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
Expand All @@ -54,7 +54,7 @@ mod tests {
use crate::nonzero;
use crate::NonEmpty;

use std::convert::TryInto;
use core::convert::TryInto;

#[test]
fn test_nonzero() {
Expand All @@ -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<()> {
Expand Down
Loading