Skip to content

Commit

Permalink
Merge pull request #52 from Gankra/nostd2
Browse files Browse the repository at this point in the history
Make thin-vec compatible with no_std
  • Loading branch information
Gankra committed Dec 3, 2023
2 parents 3996382 + 9deda74 commit b53e3b1
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 38 deletions.
14 changes: 8 additions & 6 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
run: MIRIFLAGS=-Zmiri-strict-provenance cargo miri test
- name: Test (gecko-ffi) with Miri
run: MIRIFLAGS=-Zmiri-strict-provenance cargo miri test --features=gecko-ffi

build:
runs-on: ubuntu-latest
steps:
Expand All @@ -39,7 +39,9 @@ jobs:
run: cargo test --features=serde --verbose
- name: Run tests (gecko-ffi)
run: cargo test --tests --features=gecko-ffi --verbose

- name: Run tests (no_std)
run: cargo test --tests --no-default-features --verbose

fmt:
runs-on: ubuntu-latest
steps:
Expand All @@ -54,8 +56,8 @@ jobs:
with:
command: fmt
args: --all -- --check


clippy:
runs-on: ubuntu-latest
steps:
Expand All @@ -72,8 +74,8 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace --tests --examples


docs:
runs-on: ubuntu-latest
env:
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ readme = "README.md"

[features]
unstable = []
default = []
default = ["std"]
std = []

# Gecko specific features. These features cause thin-vec to have the same layout
# and behaviour as nsTArray, allowing it to be used in C++ FFI. Requires
Expand Down
75 changes: 44 additions & 31 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,21 +141,25 @@
//!
//! [pinned]: https://doc.rust-lang.org/std/pin/index.html

#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::comparison_chain, clippy::missing_safety_doc)]

use std::alloc::*;
use std::borrow::*;
use std::cmp::*;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::hash::*;
use std::iter::FromIterator;
use std::marker::PhantomData;
use std::ops::Bound;
use std::ops::{Deref, DerefMut, RangeBounds};
use std::ptr::NonNull;
use std::slice::IterMut;
use std::{fmt, io, mem, ptr, slice};
extern crate alloc;

use alloc::alloc::*;
use alloc::{boxed::Box, vec::Vec};
use core::borrow::*;
use core::cmp::*;
use core::convert::TryFrom;
use core::convert::TryInto;
use core::hash::*;
use core::iter::FromIterator;
use core::marker::PhantomData;
use core::ops::Bound;
use core::ops::{Deref, DerefMut, RangeBounds};
use core::ptr::NonNull;
use core::slice::IterMut;
use core::{fmt, mem, ptr, slice};

use impl_details::*;

Expand Down Expand Up @@ -1124,7 +1128,7 @@ impl<T> ThinVec<T> {
min_cap_bytes.next_power_of_two() as usize
};

let cap = (bytes - std::mem::size_of::<Header>()) / elem_size;
let cap = (bytes - core::mem::size_of::<Header>()) / elem_size;
unsafe {
self.reallocate(cap);
}
Expand Down Expand Up @@ -1966,7 +1970,7 @@ impl<T> FromIterator<T> for ThinVec<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> ThinVec<T> {
let mut vec = ThinVec::new();
vec.extend(iter.into_iter());
vec.extend(iter);
vec
}
}
Expand Down Expand Up @@ -2013,7 +2017,7 @@ impl<T, const N: usize> From<[T; N]> for ThinVec<T> {
/// assert_eq!(ThinVec::from([1, 2, 3]), thin_vec![1, 2, 3]);
/// ```
fn from(s: [T; N]) -> ThinVec<T> {
std::iter::IntoIterator::into_iter(s).collect()
core::iter::IntoIterator::into_iter(s).collect()
}
}

Expand Down Expand Up @@ -2255,11 +2259,11 @@ impl<T> DoubleEndedIterator for IntoIter<T> {

impl<T> ExactSizeIterator for IntoIter<T> {}

impl<T> std::iter::FusedIterator for IntoIter<T> {}
impl<T> core::iter::FusedIterator for IntoIter<T> {}

// SAFETY: the length calculation is trivial, we're an array! And if it's wrong we're So Screwed.
#[cfg(feature = "unstable")]
unsafe impl<T> std::iter::TrustedLen for IntoIter<T> {}
unsafe impl<T> core::iter::TrustedLen for IntoIter<T> {}

impl<T> Drop for IntoIter<T> {
#[inline]
Expand Down Expand Up @@ -2421,9 +2425,9 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> {}

// SAFETY: we need to keep track of this perfectly Or Else anyway!
#[cfg(feature = "unstable")]
unsafe impl<T> std::iter::TrustedLen for Drain<'_, T> {}
unsafe impl<T> core::iter::TrustedLen for Drain<'_, T> {}

impl<T> std::iter::FusedIterator for Drain<'_, T> {}
impl<T> core::iter::FusedIterator for Drain<'_, T> {}

impl<'a, T> Drop for Drain<'a, T> {
fn drop(&mut self) {
Expand Down Expand Up @@ -2610,21 +2614,22 @@ impl<T> Drain<'_, T> {
/// Write is implemented for `ThinVec<u8>` by appending to the vector.
/// The vector will grow as needed.
/// This implementation is identical to the one for `Vec<u8>`.
impl io::Write for ThinVec<u8> {
#[cfg(feature = "std")]
impl std::io::Write for ThinVec<u8> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.extend_from_slice(buf);
Ok(buf.len())
}

#[inline]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
self.extend_from_slice(buf);
Ok(())
}

#[inline]
fn flush(&mut self) -> io::Result<()> {
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
Expand All @@ -2634,10 +2639,11 @@ impl io::Write for ThinVec<u8> {
#[cfg(test)]
mod tests {
use super::{ThinVec, MAX_CAP};
use crate::alloc::{string::ToString, vec};

#[test]
fn test_size_of() {
use std::mem::size_of;
use core::mem::size_of;
assert_eq!(size_of::<ThinVec<u8>>(), size_of::<&u8>());

assert_eq!(size_of::<Option<ThinVec<u8>>>(), size_of::<&u8>());
Expand Down Expand Up @@ -2825,6 +2831,7 @@ mod tests {
assert_eq!(v.into_iter().count(), 0);

let v = ThinVec::<i32>::new();
#[allow(clippy::never_loop)]
for _ in v.into_iter() {
unreachable!();
}
Expand All @@ -2834,6 +2841,7 @@ mod tests {
let mut v = ThinVec::<i32>::new();
assert_eq!(v.drain(..).len(), 0);

#[allow(clippy::never_loop)]
for _ in v.drain(..) {
unreachable!()
}
Expand All @@ -2847,6 +2855,7 @@ mod tests {
let mut v = ThinVec::<i32>::new();
assert_eq!(v.splice(.., []).len(), 0);

#[allow(clippy::never_loop)]
for _ in v.splice(.., []) {
unreachable!()
}
Expand Down Expand Up @@ -3010,8 +3019,12 @@ mod std_tests {
#![allow(clippy::reversed_empty_ranges)]

use super::*;
use std::mem::size_of;
use std::usize;
use crate::alloc::{
format,
string::{String, ToString},
};
use core::mem::size_of;
use core::usize;

struct DropCounter<'a> {
count: &'a mut u32,
Expand Down Expand Up @@ -3669,7 +3682,7 @@ mod std_tests {
fn test_splice_forget() {
let mut v = thin_vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
::std::mem::forget(v.splice(2..4, a.iter().cloned()));
::core::mem::forget(v.splice(2..4, a.iter().cloned()));
assert_eq!(v, &[1, 2]);
}

Expand Down Expand Up @@ -4188,16 +4201,16 @@ mod std_tests {
let v: ThinVec<$typename> = ThinVec::with_capacity(1 /* ensure allocation */);
let head_ptr: *mut $typename = v.data_raw();
assert_eq!(
head_ptr as usize % std::mem::align_of::<$typename>(),
head_ptr as usize % core::mem::align_of::<$typename>(),
0,
"expected Header::data<{}> to be aligned",
stringify!($typename)
);
}};
}

const HEADER_SIZE: usize = std::mem::size_of::<Header>();
assert_eq!(2 * std::mem::size_of::<usize>(), HEADER_SIZE);
const HEADER_SIZE: usize = core::mem::size_of::<Header>();
assert_eq!(2 * core::mem::size_of::<usize>(), HEADER_SIZE);

#[repr(C, align(128))]
struct Funky<T>(T);
Expand Down

0 comments on commit b53e3b1

Please sign in to comment.