diff --git a/.github/workflows/miri.yml b/.github/workflows/miri.yml deleted file mode 100644 index 476027a..0000000 --- a/.github/workflows/miri.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Miri - -on: - [pull_request, workflow_dispatch] - -jobs: - build: - name: Miri Test - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - features: ['', std] - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: nightly - components: miri - - run: cargo +nightly check --no-default-features --features=${{matrix.features}} - - run: cargo +nightly build --no-default-features --features=${{matrix.features}} - - run: cargo +nightly test --no-default-features --features=${{matrix.features}} - - run: cargo +nightly miri test --no-default-features --features=${{matrix.features}} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index f203a52..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Test - -on: - [pull_request, workflow_dispatch] - -jobs: - test: - name: Rust ${{matrix.rust}} - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - rust: [1.60.0, stable, beta, nightly] - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: ${{matrix.rust}} - - run: cargo check - - run: cargo build - - run: cargo test - - test-no-std: - name: Rust ${{matrix.rust}} ${{matrix.features}} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - run: cargo check --no-default-features - - run: cargo build --no-default-features - - run: cargo test --no-default-features diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 0000000..9f54011 --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,65 @@ +name: Workflow + +on: + [pull_request, workflow_dispatch] + +jobs: + test: + name: Rust ${{matrix.rust}} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: [1.60.0, stable, beta, nightly] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{matrix.rust}} + - run: cargo check + - run: cargo build + - run: cargo test + + test-no-std: + name: Rust ${{matrix.rust}} ${{matrix.features}} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - run: cargo check --no-default-features + - run: cargo build --no-default-features + - run: cargo test --no-default-features + + miri: + name: Miri Test + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + features: ['', std] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: nightly + components: miri + - run: cargo +nightly check --no-default-features --features=${{matrix.features}} + - run: cargo +nightly build --no-default-features --features=${{matrix.features}} + - run: cargo +nightly test --no-default-features --features=${{matrix.features}} + - run: cargo +nightly miri test --no-default-features --features=${{matrix.features}} + + lint: + name: Lint Crate + runs-on: ubuntu-latest + strategy: + fail-fast: true + steps: + - uses: actions/checkout@v4 + - name: Install latest nightly + uses: dtolnay/rust-toolchain@stable + with: + toolchain: nightly + components: rustfmt, clippy + - run: cargo fmt -- --check + - run: cargo clippy -- --deny warnings + - run: cargo clippy --no-default-features -- --deny warnings diff --git a/Cargo.toml b/Cargo.toml index 85c3aea..ad83d65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,5 @@ version = "1.2.0" default = ["std"] # Use the `std` library. Required for `io` support. std = [] +# internal only: enable the lint checks +lint = [] diff --git a/src/lib.rs b/src/lib.rs index 71e94d4..376d9e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,8 @@ //! 2.0 license. #![cfg_attr(not(feature = "std"), no_std)] +#![allow(unused_unsafe)] +#![cfg_attr(feature = "lint", warn(unsafe_op_in_unsafe_fn))] extern crate alloc; @@ -283,9 +285,14 @@ impl StackVec { } /// Construct a new `StackVec` from a `Vec` without bounds checking. + /// + /// # Safety + /// + /// Safe as long as `vec.len() <= N`. #[allow(deprecated)] pub unsafe fn from_vec_unchecked(vec: Vec) -> StackVec { - let mut v = Self::new(); + debug_assert!(vec.len() <= N); + let mut v: StackVec = Self::new(); let len = vec.len(); for (index, item) in vec.into_iter().enumerate() { v.data[index].write(item); @@ -344,14 +351,20 @@ impl StackVec { /// /// assert_eq!(&*stack_vec, &[1, 2, 3, 4, 5]); /// ``` + /// + /// # Safety + /// + /// Safe as long as `len <= N` and `len <= buf.len()`. #[inline] pub unsafe fn from_buf_and_len_unchecked(buf: [T; N], len: usize) -> StackVec { + debug_assert!(len <= N && len <= buf.len()); let mut v = Self::new(); { let mut local_len = SetLenOnDrop::new(&mut v.length); for (index, item) in buf.into_iter().take(len).enumerate() { v.data[index].write(item); - local_len.increment_len(1); + // SAFETY: safe as long as len <= N && len <= buf.len() + unsafe { local_len.increment_len(1) }; } } @@ -363,6 +376,10 @@ impl StackVec { /// This will explicitly set the size of the vector, without actually /// modifying its buffers, so it is up to the caller to ensure that the /// vector is actually the specified size. + /// + /// # Safety + /// + /// Safe as long as `new_len <= N`. #[inline] pub unsafe fn set_len(&mut self, new_len: usize) { debug_assert!(new_len <= N);