Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add From<Box<T>> where T: ?Sized #94

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
118 changes: 63 additions & 55 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on: [push, pull_request]

jobs:
build:

runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -13,74 +12,83 @@ jobs:
- 1.76
- nightly
steps:
- uses: actions/checkout@v4
- name: Build
run: cargo build --verbose
- name: Test
run: cargo test
- name: Test --no-default-features
run: cargo test --no-default-features --verbose
- name: Test --all-features
run: cargo test --all-features --verbose
- uses: actions/checkout@v4
- name: Install Rust ${{ matrix.rust }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust }}
override: true
Comment on lines +16 to +20
Copy link
Author

Choose a reason for hiding this comment

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

Without that the matrix value was just ignored and it was always running on stable

- name: Build
run: cargo build --verbose
- name: Test
run: cargo test
- name: Test --no-default-features
run: cargo test --no-default-features --verbose
- name: Test --all-features
if: matrix.rust == 'nightly'
run: cargo test --all-features --verbose
- name: Test --all-stable-features
if: matrix.rust != 'nightly'
run: cargo test --features "std,serde,stable_deref_trait,arc-swap,unsize" --verbose

miri:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust Nightly
run: rustup toolchain install nightly --component miri --profile minimal
- name: Miri Test
run: cargo +nightly miri test
- name: Test --no-default-features
run: cargo +nightly miri test --no-default-features
- name: Test --all-features
run: cargo +nightly miri test --all-features
- uses: actions/checkout@v4
- name: Install Rust Nightly
run: rustup toolchain install nightly --component miri --profile minimal
- name: Miri Test
run: cargo +nightly miri test
- name: Test --no-default-features
run: cargo +nightly miri test --no-default-features
- name: Test --all-features
run: cargo +nightly miri test --all-features

thread_sanitizer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ github.event.repository.name }}-${{ runner.os }}-cargo-thread_sanitizer-v2
- name: Install latest nightly
uses: actions-rs/toolchain@v1
with:
- uses: actions/checkout@v4
- uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ github.event.repository.name }}-${{ runner.os }}-cargo-thread_sanitizer-v2
- name: Install latest nightly
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
override: true
components: rust-src
- name: Run thread sanitizer
run: |
export RUSTDOCFLAGS='-Zsanitizer=thread'
export RUSTFLAGS='-Zsanitizer=thread'
for _ in $(seq 1 10); do cargo +nightly test -Z build-std --target --target $(uname -m)-unknown-linux-gnu; done
- name: Run thread sanitizer
run: |
export RUSTDOCFLAGS='-Zsanitizer=thread'
export RUSTFLAGS='-Zsanitizer=thread'
for _ in $(seq 1 10); do cargo +nightly test -Z build-std --target --target $(uname -m)-unknown-linux-gnu; done

address_sanitizer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ github.event.repository.name }}-${{ runner.os }}-cargo-address_sanitizer-v2
- name: Install latest nightly
uses: actions-rs/toolchain@v1
with:
- uses: actions/checkout@v4
- uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ github.event.repository.name }}-${{ runner.os }}-cargo-address_sanitizer-v2
- name: Install latest nightly
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
override: true
- name: Run address sanitizer
run: |
export RUSTDOCFLAGS='-Zsanitizer=address'
export RUSTFLAGS='-Zsanitizer=address'
for _ in $(seq 1 10); do cargo +nightly test; done
- name: Run address sanitizer
run: |
export RUSTDOCFLAGS='-Zsanitizer=address'
export RUSTFLAGS='-Zsanitizer=address'
for _ in $(seq 1 10); do cargo +nightly test; done
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
[package]
name = "triomphe"
version = "0.1.12"
authors = ["Manish Goregaokar <[email protected]>", "The Servo Project Developers"]
authors = [
"Manish Goregaokar <[email protected]>",
"The Servo Project Developers",
]
license = "MIT OR Apache-2.0"
repository = "https://github.com/Manishearth/triomphe"
description = "A fork of std::sync::Arc with some extra functionality and without weak references (originally servo_arc)"
Expand All @@ -13,6 +16,7 @@ rust-version = "1.76"

[features]
std = []
unstable = []
default = ["serde", "stable_deref_trait", "std"]

[package.metadata.docs.rs]
Expand Down
49 changes: 46 additions & 3 deletions src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,7 @@ impl From<String> for Arc<str> {
}
}

// FIXME: once `pointer::with_metadata_of` is stable or
// implementable on stable without assuming ptr layout
// this will be able to accept `T: ?Sized`.
#[cfg(not(feature = "unstable"))]
impl<T> From<Box<T>> for Arc<T> {
fn from(b: Box<T>) -> Self {
let layout = Layout::for_value::<T>(&b);
Expand Down Expand Up @@ -240,6 +238,43 @@ impl<T> From<Box<T>> for Arc<T> {
}
}

#[cfg(feature = "unstable")]
impl<T: ?Sized> From<Box<T>> for Arc<T> {
fn from(b: Box<T>) -> Self {
let src = Box::into_raw(b);
unsafe {
// Safety: `src` is a valid pointer
let layout = Layout::for_value_raw(src);

// Safety: the closure only changes the type of the pointer
let inner = Self::allocate_for_layout(layout, |mem| {
mem.with_metadata_of(src as *const ArcInner<T>) as *mut ArcInner<T>
});

// Safety: inner is a valid pointer, so this can't go out of bounds
let dst = addr_of_mut!((*inner.as_ptr()).data);

// Safety:
// - `src` is valid for reads (got from `Box`)
// - `dst` is valid for writes (just allocated)
// - `src` and `dst` don't overlap (separate allocations)
ptr::copy_nonoverlapping(src as *const u8, dst as *mut u8, layout.size());

// Deallocate box without dropping `T`
//
// Safety:
// - `src` has been got from `Box::into_raw`
// - `ManuallyDrop<T>` is guaranteed to have the same layout as `T`
drop(Box::<ManuallyDrop<T>>::from_raw(src as _));

Arc {
p: inner,
phantom: PhantomData,
}
}
}
}

impl<T> From<Vec<T>> for Arc<[T]> {
fn from(v: Vec<T>) -> Self {
Arc::from_header_and_vec((), v).into()
Expand Down Expand Up @@ -383,6 +418,14 @@ mod tests {
);
}

#[cfg(feature = "unstable")]
#[test]
fn from_dyn_box() {
let b = String::from("xxx").into_boxed_str();
let b = Arc::<str>::from(b);
assert_eq!(&*b, "xxx");
}

/// It’s possible to make a generic `Arc` wrapper that supports both:
///
/// * `T: !Sized`
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#![allow(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "unstable", feature(layout_for_ptr, set_ptr_value))]

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