andylokandy / smallbox Goto Github PK
View Code? Open in Web Editor NEWSmall Box optimization: store small item on stack and fallback to heap for large item.
License: MIT License
Small Box optimization: store small item on stack and fallback to heap for large item.
License: MIT License
It seems as miri test is broken. Could you please investigate it ?
Undefined Behavior: dereferencing pointer failed: 0x1fee70[noalloc] is a dangling pointer (it has no provenance)
--> src\smallbox.rs:362:18
|
362 | unsafe { &*self.as_ptr() }
| ^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x1fee70[noalloc] is a dangling pointer (it has no provenance)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `<smallbox::SmallBox<usize, space::S1> as std::ops::Deref>::deref` at src\smallbox.rs:362:18: 362:33
note: inside `smallbox::tests::test_basic`
--> src\smallbox.rs:468:17
|
468 | assert!(*stacked == 1234);
| ^^^^^^^^
note: inside closure
--> src\smallbox.rs:466:21
|
465 | #[test]
| ------- in this procedural macro expansion
466 | fn test_basic() {
| ^
= note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error
test smallbox::tests::test_basic ... error: test failed, to rerun pass `--lib`
Caused by:
process didn't exit successfully: `C:\Users\zpgaa\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\bin\cargo-miri.exe runner D:\work\3rdparty\smallbox\target\miri\x86_64-pc-windows-msvc\debug\deps\smallbox-932a3225d7a60a4d.exe` (exit code: 1)
smallbox on ๎ master is ๐ฆ v0.8.1 via ๐ฆ v1.69.0-nightly took 2s
Difference in definitions of new
depending on a feature flag makes it impossible to create a simple sized box when needed. For example, the following code:
struct S { data: usize, }
let m = StackBox::<S, S1>::new(S { data: 10 }).unwrap();
compiles fine with default features, but fails with unsize
with
the trait
std::marker::Unsize<stackbox::tests::test_as_ptr::S>
is not implemented forstackbox::tests::test_as_ptr::S
I'd suggest exposing same basic interface for sized values via new
and create a separate feature-controlled new_unsized
for when it's needed, so that compiler can distinguish and correctly resolve types in both cases.
While the latest "Migrate to Rust 1.36" commit does make an attempt to use MaybeUninit
, the way it's used is still UB because assume_init
is called on uninitialized values: ManuallyDrop::new(mem::MaybeUninit::<Space>::uninit().assume_init())
.
It should be possible to avoid this by replacing ManuallyDrop
with MaybeUninit
directly in the struct.
Implementing this feature will increase 1 byte of StackBox<T>
to store the length of T. Anyway, if we have already stored the length, we could opt out SmallBox<T>
's enum tag by refactoring it to untagged_union, and produce a pattern-matchable enum by some method(unpack()?).
Even though Unsize
and CoerceUnsized
traits are not available on stable Rust, the code casting between compatible sized/unsized variants is still valid and compilable, just can't be expressed via the type system and generics.
This makes me wonder: would it make sense to add top-level macro for stackbox
and smallbox
? They would basically contain same code as new
currently has (most importantly - casts between &T
and &U
, everything else can be still hidden into methods), and when expanded, these casts would be validated even by stable Rust, allowing to create unsized SmallBoxes.
Hello.
I can't build this library for STM32.
error[E0405]: cannot find trait `Ord` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:442:30
|
442 | impl<T: ?Sized + Ord, Space> Ord for SmallBox<T, Space> {
| ^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::cmp::Ord;
|
error[E0405]: cannot find trait `Sized` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:442:10
|
442 | impl<T: ?Sized + Ord, Space> Ord for SmallBox<T, Space> {
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::marker::Sized;
|
error[E0405]: cannot find trait `Ord` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:442:18
|
442 | impl<T: ?Sized + Ord, Space> Ord for SmallBox<T, Space> {
| ^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::cmp::Ord;
|
error[E0433]: failed to resolve: use of undeclared type `Ord`
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:444:9
|
444 | Ord::cmp(&**self, &**other)
| ^^^ use of undeclared type `Ord`
|
help: consider importing this trait
|
1 + use core::cmp::Ord;
|
error[E0405]: cannot find trait `Eq` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:448:29
|
448 | impl<T: ?Sized + Eq, Space> Eq for SmallBox<T, Space> {}
| ^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::cmp::Eq;
|
error[E0405]: cannot find trait `Sized` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:448:10
|
448 | impl<T: ?Sized + Eq, Space> Eq for SmallBox<T, Space> {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::marker::Sized;
|
error[E0405]: cannot find trait `Eq` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:448:18
|
448 | impl<T: ?Sized + Eq, Space> Eq for SmallBox<T, Space> {}
| ^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::cmp::Eq;
|
error[E0405]: cannot find trait `Sized` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:450:10
|
450 | impl<T: ?Sized + Hash, Space> Hash for SmallBox<T, Space> {
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::marker::Sized;
|
error[E0405]: cannot find trait `Send` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:456:38
|
456 | unsafe impl<T: ?Sized + Send, Space> Send for SmallBox<T, Space> {}
| ^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::marker::Send;
|
error[E0405]: cannot find trait `Sized` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:456:17
|
456 | unsafe impl<T: ?Sized + Send, Space> Send for SmallBox<T, Space> {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::marker::Sized;
|
error[E0405]: cannot find trait `Send` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:456:25
|
456 | unsafe impl<T: ?Sized + Send, Space> Send for SmallBox<T, Space> {}
| ^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::marker::Send;
|
error[E0405]: cannot find trait `Sync` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:457:38
|
457 | unsafe impl<T: ?Sized + Sync, Space> Sync for SmallBox<T, Space> {}
| ^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::marker::Sync;
|
error[E0405]: cannot find trait `Sized` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:457:17
|
457 | unsafe impl<T: ?Sized + Sync, Space> Sync for SmallBox<T, Space> {}
| ^^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::marker::Sized;
|
error[E0405]: cannot find trait `Sync` in this scope
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/smallbox.rs:457:25
|
457 | unsafe impl<T: ?Sized + Sync, Space> Sync for SmallBox<T, Space> {}
| ^^^^ not found in this scope
|
help: consider importing this trait
|
1 + use core::marker::Sync;
|
error[E0554]: `#![feature]` may not be used on the stable release channel
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/lib.rs:152:33
|
152 | #![cfg_attr(feature = "coerce", feature(unsize, coerce_unsized))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0554]: `#![feature]` may not be used on the stable release channel
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/lib.rs:153:35
|
153 | #![cfg_attr(not(feature = "std"), feature(cfg_doctest))]
| ^^^^^^^^^^^^^^^^^^^^ help: remove the attribute
|
= help: the feature `cfg_doctest` has been stable since `1.40.0` and no longer requires an attribute to enable
error[E0554]: `#![feature]` may not be used on the stable release channel
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/lib.rs:152:41
|
152 | #![cfg_attr(feature = "coerce", feature(unsize, coerce_unsized))]
| ^^^^^^
error[E0554]: `#![feature]` may not be used on the stable release channel
--> /home/mhanusek/.cargo/registry/src/index.crates.io-6f17d22bba15001f/smallbox-0.8.1/src/lib.rs:152:49
|
152 | #![cfg_attr(feature = "coerce", feature(unsize, coerce_unsized))]
| ^^^^^^^^^^^^^^
I Added this:
[dependencies.smallbox]
version = "0.8"
features = ["coerce"]
default-features = false
Smallbox with size set in bytes always returns .is_heap() -> true, and performs worse then S8 equivalent on 64bit machine (probably because it really uses heap). std::mem::sizeof() for both is 72 bytes. From the limited tests i did, custom byte size box always uses heap, no matter the size chosen.
StackBox and SmallBox currently expect any data to be aligned to usize
but in reality type can have arbitrarily large alignment, and putting it into usize-aligned stack storage can cause all sorts of platform-specific issues.
While there is currently no way to allocate on stack with custom alignment, constructors of these types should at least check that alignment of type not any larger than the expected one, similarly to how they already check type sizes.
I think it would be useful to include a pin
function analogous to Box::pin
. Would that be safe? It could help with async traits.
Ideally, unsafe blocks should be minimized. In particular new_copy
runs afoul of rust-lang/rfcs#2585 It's the write and transmute that requires unsafe?
I suppose your lines like ptr_ptr.write(ptr_addr as usize);
could document that they overwrite the pointer but retain any extra data inside the fat pointer.
I found the double arguments to new_copy
and new_unchecked
confusing, but some explanation comes with the smallbox!
macro. We've a type argument T
of SmallBox<T, Space>
giving the unsized trait object or slice, but you also provide a sized argument U
that provides a underlying sized type, such as a fixed length array. Ain't so idiomatic to pass around multiple references though, but I suppose this hack supports unsized types on stable without the CoerceUnsized
nightly feature.
Why use std::alloc::{alloc.Layout}
directly when seemingly Box
methods suffice?
^
error[E0080]: constant evaluation error: no item to reborrow for Unique from tag 93741 found in borrow stack
--> src/smallbox.rs:319:18
|
319 | unsafe { &mut *(self.as_ptr() as *const _ as *mut _) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item to reborrow for Unique from tag 93741 found in borrow stack
|
note: inside call to `<smallbox::SmallBox<usize, space::S1> as std::ops::DerefMut>::deref_mut` at src/smallbox.rs:327:42
--> src/smallbox.rs:327:42
|
327 | ptr::drop_in_place::<T>(&mut **self);
| ^^^^^^
= note: inside call to `<smallbox::SmallBox<usize, space::S1> as std::ops::Drop>::drop` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libcore/ptr.rs:193:1
note: inside call to `std::ptr::real_drop_in_place::<smallbox::SmallBox<usize, space::S1>> - shim(Some(smallbox::SmallBox<usize, space::S1>))` at src/smallbox.rs:423:5
--> src/smallbox.rs:423:5
|
423 | }
| ^
note: inside call to `smallbox::tests::test_basic` at src/smallbox.rs:417:5
--> src/smallbox.rs:417:5
|
417 | / fn test_basic() {
418 | | let stacked: SmallBox<usize, S1> = SmallBox::new(1234usize);
419 | | assert!(*stacked == 1234);
420 | |
421 | | let heaped: SmallBox<(usize, usize), S1> = SmallBox::new((0, 1));
422 | | assert!(*heaped == (0, 1));
423 | | }
| |_____^
= note: inside call to closure at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libcore/ops/function.rs:231:5
= note: inside call to `<[closure@src/smallbox.rs:417:5: 423:6] as std::ops::FnOnce<()>>::call_once - shim` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libcore/ops/function.rs:231:5
= note: inside call to `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libtest/lib.rs:1522:5
= note: inside call to `test::__rust_begin_short_backtrace::<fn()>` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libtest/lib.rs:1513:30
= note: inside call to closure at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libcore/ops/function.rs:231:5
= note: inside call to `<[closure@DefId(9/1:109 ~ test[b0fc]::run_test[0]::{{closure}}[3]) 0:fn()] as std::ops::FnOnce<()>>::call_once - shim` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libcore/ops/function.rs:231:5
= note: inside call to `<[closure@DefId(9/1:109 ~ test[b0fc]::run_test[0]::{{closure}}[3]) 0:fn()] as std::ops::FnOnce<()>>::call_once - shim(vtable)` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/liballoc/boxed.rs:704:9
= note: inside call to `<std::boxed::Box<dyn std::boxed::FnBox<(), Output = ()> + std::marker::Send> as std::ops::FnOnce<()>>::call_once` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/panic.rs:309:9
= note: inside call to `<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::boxed::FnBox<(), Output = ()> + std::marker::Send>> as std::ops::FnOnce<()>>::call_once` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/panicking.rs:293:40
= note: inside call to `std::panicking::try::do_call::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::boxed::FnBox<(), Output = ()> + std::marker::Send>>, ()>` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/panicking.rs:289:5
= note: inside call to `std::panicking::try::<(), std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::boxed::FnBox<(), Output = ()> + std::marker::Send>>>` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/panic.rs:388:9
= note: inside call to `std::panic::catch_unwind::<std::panic::AssertUnwindSafe<std::boxed::Box<dyn std::boxed::FnBox<(), Output = ()> + std::marker::Send>>, ()>` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libtest/lib.rs:1468:26
= note: inside call to closure at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libtest/lib.rs:1490:13
= note: inside call to `test::run_test::run_test_inner` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libtest/lib.rs:1509:28
= note: inside call to `test::run_test` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libtest/lib.rs:1167:13
= note: inside call to `test::run_tests::<[closure@DefId(9/1:80 ~ test[b0fc]::run_tests_console[0]::{{closure}}[2]) 0:&mut test::ConsoleTestState, 1:&mut std::boxed::Box<dyn test::formatters::OutputFormatter>]>` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libtest/lib.rs:972:5
= note: inside call to `test::run_tests_console` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libtest/lib.rs:293:15
= note: inside call to `test::test_main` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libtest/lib.rs:327:5
= note: inside call to `test::test_main_static`
= note: inside call to `main` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/rt.rs:64:34
= note: inside call to closure at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/rt.rs:52:53
= note: inside call to closure at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/panicking.rs:293:40
= note: inside call to `std::panicking::try::do_call::<[closure@DefId(1/1:1835 ~ std[797b]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/panicking.rs:289:5
= note: inside call to `std::panicking::try::<i32, [closure@DefId(1/1:1835 ~ std[797b]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe]>` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/panic.rs:388:9
= note: inside call to `std::panic::catch_unwind::<[closure@DefId(1/1:1835 ~ std[797b]::rt[0]::lang_start_internal[0]::{{closure}}[0]) 0:&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe], i32>` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/rt.rs:52:25
= note: inside call to `std::rt::lang_start_internal` at /Users/jrmuizel/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libstd/rt.rs:64:5
= note: inside call to `std::rt::lang_start::<()>`
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.