--- thunderbird-78.9.0/Cargo.lock.D87019-thin-vec-big-endian.diff 2021-03-22 11:34:35.584716638 +0100 +++ thunderbird-78.9.0/Cargo.lock 2021-03-22 12:29:14.140624979 +0100 @@ -4792,9 +4792,9 @@ checksum = "8eaa81235c7058867fa8c0e7314f [[package]] name = "thin-vec" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a93c9ade36a827a69257925808463db46ffcf193442fad01eb9bdc1d31aed81" +checksum = "dcc760ada4a9f56fc6d0e81bd143984ebc7bb1b875a6891aa2fa613ca7394fc0" [[package]] name = "thiserror" --- thunderbird-78.9.0/gfx/webrender_bindings/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:35:16.000000000 +0100 +++ thunderbird-78.9.0/gfx/webrender_bindings/Cargo.toml 2021-03-22 11:34:35.587716631 +0100 @@ -20,7 +20,7 @@ nsstring = { path = "../../xpcom/rust/ns bincode = "1.0" uuid = { version = "0.8", features = ["v4"] } fxhash = "0.2.1" -thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } swgl = { path = "../wr/swgl" } [dependencies.webrender] --- thunderbird-78.9.0/intl/l10n/rust/fluent-ffi/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:35:16.000000000 +0100 +++ thunderbird-78.9.0/intl/l10n/rust/fluent-ffi/Cargo.toml 2021-03-22 11:34:35.589716625 +0100 @@ -10,4 +10,4 @@ fluent-pseudo = "0.2" intl-memoizer = "0.4" unic-langid = "0.8" nsstring = { path = "../../../../xpcom/rust/nsstring" } -thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } --- thunderbird-78.9.0/intl/locale/rust/fluent-langneg-ffi/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:35:16.000000000 +0100 +++ thunderbird-78.9.0/intl/locale/rust/fluent-langneg-ffi/Cargo.toml 2021-03-22 11:34:35.590716623 +0100 @@ -9,7 +9,7 @@ edition = "2018" nserror = { path = "../../../../xpcom/rust/nserror" } nsstring = { path = "../../../../xpcom/rust/nsstring" } xpcom = { path = "../../../../xpcom/rust/xpcom" } -thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } fluent-langneg = { version = "0.12.1", features = ["cldr"] } unic-langid = "0.8" unic-langid-ffi = { path = "../unic-langid-ffi" } --- thunderbird-78.9.0/intl/locale/rust/unic-langid-ffi/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:35:16.000000000 +0100 +++ thunderbird-78.9.0/intl/locale/rust/unic-langid-ffi/Cargo.toml 2021-03-22 11:34:35.591716620 +0100 @@ -9,5 +9,5 @@ edition = "2018" nserror = { path = "../../../../xpcom/rust/nserror" } nsstring = { path = "../../../../xpcom/rust/nsstring" } xpcom = { path = "../../../../xpcom/rust/xpcom" } -thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } unic-langid = { version = "0.8", features = ["likelysubtags"] } --- thunderbird-78.9.0/netwerk/socket/neqo_glue/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:35:40.000000000 +0100 +++ thunderbird-78.9.0/netwerk/socket/neqo_glue/Cargo.toml 2021-03-22 11:34:35.600716597 +0100 @@ -14,7 +14,7 @@ neqo-common = { tag = "v0.2.4", git = "h nserror = { path = "../../../xpcom/rust/nserror" } nsstring = { path = "../../../xpcom/rust/nsstring" } xpcom = { path = "../../../xpcom/rust/xpcom" } -thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } [dependencies.neqo-crypto] tag = "v0.2.4" --- thunderbird-78.9.0/security/manager/ssl/cert_storage/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:35:52.000000000 +0100 +++ thunderbird-78.9.0/security/manager/ssl/cert_storage/Cargo.toml 2021-03-22 11:34:35.601716594 +0100 @@ -18,6 +18,6 @@ rust_cascade = "0.6.0" sha2 = "^0.8" storage_variant = { path = "../../../../storage/variant" } tempfile = "3" -thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } time = "0.1" xpcom = { path = "../../../../xpcom/rust/xpcom" } --- thunderbird-78.9.0/services/fxaccounts/rust-bridge/firefox-accounts-bridge/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:35:49.000000000 +0100 +++ thunderbird-78.9.0/services/fxaccounts/rust-bridge/firefox-accounts-bridge/Cargo.toml 2021-03-22 11:34:35.603716589 +0100 @@ -20,5 +20,5 @@ nserror = { path = "../../../../xpcom/ru nsstring = { path = "../../../../xpcom/rust/nsstring" } xpcom = { path = "../../../../xpcom/rust/xpcom" } storage_variant = { path = "../../../../storage/variant" } -thin-vec = { version = "0.1", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } fxa-client = { git = "https://github.com/mozilla/application-services", rev = "61dcc364ac0d6d0816ab88a494bbf20d824b009b", features = ["gecko"] } --- thunderbird-78.9.0/services/sync/golden_gate/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:35:53.000000000 +0100 +++ thunderbird-78.9.0/services/sync/golden_gate/Cargo.toml 2021-03-22 11:34:35.605716584 +0100 @@ -19,5 +19,5 @@ sync15-traits = { git = "https://github. xpcom = { path = "../../../xpcom/rust/xpcom" } [dependencies.thin-vec] -version = "0.1.0" +version = "0.2.1" features = ["gecko-ffi"] --- thunderbird-78.9.0/third_party/rust/thin-vec/.cargo-checksum.json.D87019-thin-vec-big-endian.diff 2021-03-22 11:34:35.606716581 +0100 +++ thunderbird-78.9.0/third_party/rust/thin-vec/.cargo-checksum.json 2021-03-22 12:30:38.588587238 +0100 @@ -1 +1 @@ -{"files":{"Cargo.toml":"7b164cc8a702a204a4732cb4da2940711b8e3be915c258e2a972d4874d767b4c","README.md":"c26d7101e3031e7dd8890ce938e50cad7a1e6adf7fc2f2b0d3c36b03afe68c0b","src/lib.rs":"9f2a087cabfe0b6f83818323bb9004b45fe7548c51376816fd8d4572256bd0e8","src/range.rs":"bac59bcb6230367a39c7e28ac15263e4526f966cd8c72015873017f17c115aaa"},"package":"3a93c9ade36a827a69257925808463db46ffcf193442fad01eb9bdc1d31aed81"} \ No newline at end of file +{"files":{"Cargo.toml":"754c05523d17eb7591c3ea2c9294e47c05fbb257fed04b78546fb2ec7cafa8b4","README.md":"c26d7101e3031e7dd8890ce938e50cad7a1e6adf7fc2f2b0d3c36b03afe68c0b","src/lib.rs":"627c6094c3f0286dba25bc73f5672c06c5061c25b01c513d213cbdda100673a2"},"package":"dcc760ada4a9f56fc6d0e81bd143984ebc7bb1b875a6891aa2fa613ca7394fc0"} --- thunderbird-78.9.0/third_party/rust/thin-vec/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:36:33.000000000 +0100 +++ thunderbird-78.9.0/third_party/rust/thin-vec/Cargo.toml 2021-03-22 12:32:38.577621737 +0100 @@ -11,8 +11,9 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "thin-vec" -version = "0.1.2" +version = "0.2.1" authors = ["Alexis Beingessner "] description = "a vec that takes up less space on the stack" homepage = "https://github.com/gankro/thin-vec" --- thunderbird-78.9.0/third_party/rust/thin-vec/src/lib.rs.D87019-thin-vec-big-endian.diff 2021-03-19 22:36:28.000000000 +0100 +++ thunderbird-78.9.0/third_party/rust/thin-vec/src/lib.rs 2021-03-22 12:34:10.271595434 +0100 @@ -1,47 +1,252 @@ -mod range; +//! ThinVec is exactly the same as Vec, except that it stores its `len` and `capacity` in the buffer +//! it allocates. +//! +//! This makes the memory footprint of ThinVecs lower; notably in cases where space is reserved for +//! a non-existence ThinVec. So `Vec>` and `Option>::None` will waste less +//! space. Being pointer-sized also means it can be passed/stored in registers. +//! +//! Of course, any actually constructed ThinVec will theoretically have a bigger allocation, but +//! the fuzzy nature of allocators means that might not actually be the case. +//! +//! Properties of Vec that are preserved: +//! * `ThinVec::new()` doesn't allocate (it points to a statically allocated singleton) +//! * reallocation can be done in place +//! * `size_of::>()` == `size_of::>>()` +//! +//! Properties of Vec that aren't preserved: +//! * `ThinVec` can't ever be zero-cost roundtripped to a `Box<[T]>`, `String`, or `*mut T` +//! * `from_raw_parts` doesn't exist +//! * ThinVec currently doesn't bother to not-allocate for Zero Sized Types (e.g. `ThinVec<()>`), +//! but it could be done if someone cared enough to implement it. +//! +//! +//! +//! # Gecko FFI +//! +//! If you enable the gecko-ffi feature, ThinVec will verbatim bridge with the nsTArray type in +//! Gecko (Firefox). That is, ThinVec and nsTArray have identical layouts *but not ABIs*, +//! so nsTArrays/ThinVecs an be natively manipulated by C++ and Rust, and ownership can be +//! transferred across the FFI boundary (**IF YOU ARE CAREFUL, SEE BELOW!!**). +//! +//! While this feature is handy, it is also inherently dangerous to use because Rust and C++ do not +//! know about eachother. Specifically, this can be an issue with non-POD types (types which +//! have destructors, move constructors, or are `!Copy`). +//! +//! ## Do Not Pass By Value +//! +//! The biggest thing to keep in mind is that **FFI functions cannot pass ThinVec/nsTArray +//! by-value**. That is, these are busted APIs: +//! +//! ```rust,ignore +//! // BAD WRONG +//! extern fn process_data(data: ThinVec) { ... } +//! // BAD WRONG +//! extern fn get_data() -> ThinVec { ... } +//! ``` +//! +//! You must instead pass by-reference: +//! +//! ```rust +//! # use thin_vec::*; +//! # use std::mem; +//! +//! // Read-only access, ok! +//! extern fn process_data(data: &ThinVec) { +//! for val in data { +//! println!("{}", val); +//! } +//! } +//! +//! // Replace with empty instance to take ownership, ok! +//! extern fn consume_data(data: &mut ThinVec) { +//! let owned = mem::replace(data, ThinVec::new()); +//! mem::drop(owned); +//! } +//! +//! // Mutate input, ok! +//! extern fn add_data(dataset: &mut ThinVec) { +//! dataset.push(37); +//! dataset.push(12); +//! } +//! +//! // Return via out-param, usually ok! +//! // +//! // WARNING: output must be initialized! (Empty nsTArrays are free, so just do it!) +//! extern fn get_data(output: &mut ThinVec) { +//! *output = thin_vec![1, 2, 3, 4, 5]; +//! } +//! ``` +//! +//! Ignorable Explanation For Those Who Really Want To Know Why: +//! +//! > The fundamental issue is that Rust and C++ can't currently communicate about destructors, and +//! > the semantics of C++ require destructors of function arguments to be run when the function +//! > returns. Whether the callee or caller is responsible for this is also platform-specific, so +//! > trying to hack around it manually would be messy. +//! > +//! > Also a type having a destructor changes its C++ ABI, because that type must actually exist +//! > in memory (unlike a trivial struct, which is often passed in registers). We don't currently +//! > have a way to communicate to Rust that this is happening, so even if we worked out the +//! > destructor issue with say, MaybeUninit, it would still be a non-starter without some RFCs +//! > to add explicit rustc support. +//! > +//! > Realistically, the best answer here is to have a "heavier" bindgen that can secretly +//! > generate FFI glue so we can pass things "by value" and have it generate by-reference code +//! > behind our back (like the cxx crate does). This would muddy up debugging/searchfox though. +//! +//! ## Types Should Be Trivially Relocatable +//! +//! Types in Rust are always trivially relocatable (unless suitably borrowed/[pinned][]/hidden). +//! This means all Rust types are legal to relocate with a bitwise copy, you cannot provide +//! copy or move constructors to execute when this happens, and the old location won't have its +//! destructor run. This will cause problems for types which have a significant location +//! (types that intrusively point into themselves or have their location registered with a service). +//! +//! While relocations are generally predictable if you're very careful, **you should avoid using +//! types with significant locations with Rust FFI**. +//! +//! Specifically, ThinVec will trivially relocate its contents whenever it needs to reallocate its +//! buffer to change its capacity. This is the default reallocation strategy for nsTArray, and is +//! suitable for the vast majority of types. Just be aware of this limitation! +//! +//! ## Auto Arrays Are Dangerous +//! +//! ThinVec has *some* support for handling auto arrays which store their buffer on the stack, +//! but this isn't well tested. +//! +//! Regardless of how much support we provide, Rust won't be aware of the buffer's limited lifetime, +//! so standard auto array safety caveats apply about returning/storing them! ThinVec won't ever +//! produce an auto array on its own, so this is only an issue for transferring an nsTArray into +//! Rust. +//! +//! ## Other Issues +//! +//! Standard FFI caveats also apply: +//! +//! * Rust is more strict about POD types being initialized (use MaybeUninit if you must) +//! * `ThinVec` has no idea if the C++ version of `T` has move/copy/assign/delete overloads +//! * `nsTArray` has no idea if the Rust version of `T` has a Drop/Clone impl +//! * C++ can do all sorts of unsound things that Rust can't catch +//! * C++ and Rust don't agree on how zero-sized/empty types should be handled +//! +//! The gecko-ffi feature will not work if you aren't linking with code that has nsTArray +//! defined. Specifically, we must share the symbol for nsTArray's empty singleton. You will get +//! linking errors if that isn't defined. +//! +//! The gecko-ffi feature also limits ThinVec to the legacy behaviors of nsTArray. Most notably, +//! nsTArray has a maximum capacity of i32::MAX (~2.1 billion items). Probably not an issue. +//! Probably. +//! +//! [pinned]: https://doc.rust-lang.org/std/pin/index.html use std::{fmt, io, ptr, mem, slice}; use std::collections::Bound; use std::iter::FromIterator; use std::slice::IterMut; -use std::ops::{Deref, DerefMut}; +use std::ops::{Deref, DerefMut, RangeBounds}; use std::marker::PhantomData; use std::alloc::*; use std::cmp::*; use std::hash::*; use std::borrow::*; -use range::RangeArgument; use std::ptr::NonNull; -#[cfg(not(feature = "gecko-ffi"))] -type SizeType = usize; -#[cfg(feature = "gecko-ffi")] -type SizeType = u32; +use impl_details::*; -#[cfg(feature = "gecko-ffi")] -const AUTO_MASK: u32 = 1 << 31; -#[cfg(feature = "gecko-ffi")] -const CAP_MASK: u32 = !AUTO_MASK; +// modules: a simple way to cfg a whole bunch of impl details at once #[cfg(not(feature = "gecko-ffi"))] -const MAX_CAP: usize = !0; -#[cfg(feature = "gecko-ffi")] -const MAX_CAP: usize = i32::max_value() as usize; +mod impl_details { + pub type SizeType = usize; + pub const MAX_CAP: usize = !0; -#[cfg(not(feature = "gecko-ffi"))] -#[inline(always)] -fn assert_size(x: usize) -> SizeType { x } + #[inline(always)] + pub fn assert_size(x: usize) -> SizeType { x } +} #[cfg(feature = "gecko-ffi")] -#[inline] -fn assert_size(x: usize) -> SizeType { - if x > MAX_CAP as usize { - panic!("nsTArray size may not exceed the capacity of a 32-bit sized int"); +mod impl_details { + // Support for briding a gecko nsTArray verbatim into a ThinVec. + // + // ThinVec can't see copy/move/delete implementations + // from C++ + // + // The actual layout of an nsTArray is: + // + // ```cpp + // struct { + // uint32_t mLength; + // uint32_t mCapacity: 31; + // uint32_t mIsAutoArray: 1; + // } + // ``` + // + // Rust doesn't natively support bit-fields, so we manually mask + // and shift the bit. When the "auto" bit is set, the header and buffer + // are actually on the stack, meaning the ThinVec pointer-to-header + // is essentially an "owned borrow", and therefore dangerous to handle. + // There are no safety guards for this situation. + // + // On little-endian platforms, the auto bit will be the high-bit of + // our capacity u32. On big-endian platforms, it will be the low bit. + // Hence we need some platform-specific CFGs for the necessary masking/shifting. + // + // ThinVec won't ever construct an auto array. They only happen when + // bridging from C++. This means we don't need to ever set/preserve the bit. + // We just need to be able to read and handle it if it happens to be there. + // + // Handling the auto bit mostly just means not freeing/reallocating the buffer. + + pub type SizeType = u32; + + pub const MAX_CAP: usize = i32::max_value() as usize; + + // Little endian: the auto bit is the high bit, and the capacity is + // verbatim. So we just need to mask off the high bit. Note that + // this masking is unnecessary when packing, because assert_size + // guards against the high bit being set. + #[cfg(target_endian = "little")] + pub fn pack_capacity(cap: SizeType) -> SizeType { + cap as SizeType + } + #[cfg(target_endian = "little")] + pub fn unpack_capacity(cap: SizeType) -> usize { + (cap as usize) & !(1 << 31) + } + #[cfg(target_endian = "little")] + pub fn is_auto(cap: SizeType) -> bool { + (cap & (1 << 31)) != 0 + } + + // Big endian: the auto bit is the low bit, and the capacity is + // shifted up one bit. Masking out the auto bit is unnecessary, + // as rust shifts always shift in 0's for unsigned integers. + #[cfg(target_endian = "big")] + pub fn pack_capacity(cap: SizeType) -> SizeType { + (cap as SizeType) << 1 + } + #[cfg(target_endian = "big")] + pub fn unpack_capacity(cap: SizeType) -> usize { + (cap >> 1) as usize + } + #[cfg(target_endian = "big")] + pub fn is_auto(cap: SizeType) -> bool { + (cap & 1) != 0 } - x as SizeType + + #[inline] + pub fn assert_size(x: usize) -> SizeType { + if x > MAX_CAP as usize { + panic!("nsTArray size may not exceed the capacity of a 32-bit sized int"); + } + x as SizeType + } + } -/// The header of a ThinVec +/// The header of a ThinVec. +/// +/// The _cap can be a bitfield, so use accessors to avoid trouble. #[repr(C)] struct Header { _len: SizeType, @@ -53,38 +258,10 @@ impl Header { self._len as usize } - #[cfg(feature = "gecko-ffi")] - fn cap(&self) -> usize { - (self._cap & CAP_MASK) as usize - } - - #[cfg(not(feature = "gecko-ffi"))] - fn cap(&self) -> usize { - self._cap as usize - } - fn set_len(&mut self, len: usize) { self._len = assert_size(len); } - #[cfg(feature = "gecko-ffi")] - fn set_cap(&mut self, cap: usize) { - debug_assert!(cap & (CAP_MASK as usize) == cap); - // FIXME: this is busted because it reads uninit memory - // debug_assert!(!self.uses_stack_allocated_buffer()); - self._cap = assert_size(cap) & CAP_MASK; - } - - #[cfg(feature = "gecko-ffi")] - fn uses_stack_allocated_buffer(&self) -> bool { - self._cap & AUTO_MASK != 0 - } - - #[cfg(not(feature = "gecko-ffi"))] - fn set_cap(&mut self, cap: usize) { - self._cap = assert_size(cap); - } - fn data(&self) -> *mut T { let header_size = mem::size_of::
(); let padding = padding::(); @@ -102,6 +279,41 @@ impl Header { } } + +#[cfg(feature = "gecko-ffi")] +impl Header { + fn cap(&self) -> usize { + unpack_capacity(self._cap) + } + + fn set_cap(&mut self, cap: usize) { + // debug check that our packing is working + debug_assert_eq!(unpack_capacity(pack_capacity(cap as SizeType)), cap); + // FIXME: this assert is busted because it reads uninit memory + // debug_assert!(!self.uses_stack_allocated_buffer()); + + // NOTE: this always stores a cleared auto bit, because set_cap + // is only invoked by Rust, and Rust doesn't create auto arrays. + self._cap = pack_capacity(assert_size(cap)); + } + + fn uses_stack_allocated_buffer(&self) -> bool { + is_auto(self._cap) + } +} + +#[cfg(not(feature = "gecko-ffi"))] +impl Header { + fn cap(&self) -> usize { + self._cap as usize + } + + fn set_cap(&mut self, cap: usize) { + self._cap = assert_size(cap); + } +} + + /// Singleton that all empty collections share. /// Note: can't store non-zero ZSTs, we allocate in that case. We could /// optimize everything to not do that (basically, make ptr == len and branch @@ -118,9 +330,7 @@ extern { // TODO: overflow checks everywhere -// Utils - -fn oom() -> ! { std::process::abort() } +// Utils for computing layouts of allocations fn alloc_size(cap: usize) -> usize { // Compute "real" header size with pointer math @@ -165,9 +375,10 @@ fn layout(cap: usize) -> Layout { fn header_with_capacity(cap: usize) -> NonNull
{ debug_assert!(cap > 0); unsafe { - let header = alloc(layout::(cap)) as *mut Header; + let layout = layout::(cap); + let header = alloc(layout) as *mut Header; - if header.is_null() { oom() } + if header.is_null() { handle_alloc_error(layout) } // "Infinite" capacity for zero-sized types: (*header).set_cap(if mem::size_of::() == 0 { MAX_CAP } else { cap }); @@ -179,28 +390,8 @@ fn header_with_capacity(cap: usize) - -/// ThinVec is exactly the same as Vec, except that it stores its `len` and `capacity` in the buffer -/// it allocates. -/// -/// This makes the memory footprint of ThinVecs lower; notably in cases where space is reserved for -/// a non-existence ThinVec. So `Vec>` and `Option>::None` will waste less -/// space. Being pointer-sized also means it can be passed/stored in registers. -/// -/// Of course, any actually constructed ThinVec will theoretically have a bigger allocation, but -/// the fuzzy nature of allocators means that might not actually be the case. -/// -/// Properties of Vec that are preserved: -/// * `ThinVec::new()` doesn't allocate (it points to a statically allocated singleton) -/// * reallocation can be done in place -/// * `size_of::>()` == `size_of::>>()` -/// * NOTE: This is only possible when the `unstable` feature is used. -/// -/// Properties of Vec that aren't preserved: -/// * `ThinVec` can't ever be zero-cost roundtripped to a `Box<[T]>`, `String`, or `*mut T` -/// * `from_raw_parts` doesn't exist -/// * ThinVec currently doesn't bother to not-allocate for Zero Sized Types (e.g. `ThinVec<()>`), -/// but it could be done if someone cared enough to implement it. -#[cfg_attr(feature = "gecko-ffi", repr(C))] +/// See the crate's top level documentation for a description of this type. +#[repr(C)] pub struct ThinVec { ptr: NonNull
, boo: PhantomData, @@ -630,15 +821,15 @@ impl ThinVec { } pub fn drain(&mut self, range: R) -> Drain - where R: RangeArgument + where R: RangeBounds { let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Bound::Included(&n) => n, Bound::Excluded(&n) => n + 1, Bound::Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Bound::Included(&n) => n + 1, Bound::Excluded(&n) => n, Bound::Unbounded => len, @@ -688,11 +879,30 @@ impl ThinVec { alloc_size::(new_cap), ) as *mut Header; - if ptr.is_null() { oom() } + if ptr.is_null() { handle_alloc_error(layout::(new_cap)) } (*ptr).set_cap(new_cap); self.ptr = NonNull::new_unchecked(ptr); } else { - self.ptr = header_with_capacity::(new_cap); + let mut new_header = header_with_capacity::(new_cap); + + // If we get here and have a non-zero len, then we must be handling + // a gecko auto array, and we have items in a stack buffer. We shouldn't + // free it, but we should memcopy the contents out of it and mark it as empty. + // + // T is assumed to be trivially relocatable, as this is ~required + // for Rust compatibility anyway. Furthermore, we assume C++ won't try + // to unconditionally destroy the contents of the stack allocated buffer + // (i.e. it's obfuscated behind a union). + // + // In effect, we are partially reimplementing the auto array move constructor + // by leaving behind a valid empty instance. + let len = self.len(); + if cfg!(feature = "gecko-ffi") && len > 0 { + new_header.as_mut().data::().copy_from_nonoverlapping(self.data_raw(), len); + self.set_len(0); + } + + self.ptr = new_header; } } @@ -1093,10 +1303,7 @@ mod tests { use std::mem::size_of; assert_eq!(size_of::>(), size_of::<&u8>()); - // We don't perform the null-pointer optimization on stable rust. - if cfg!(feature = "unstable") { - assert_eq!(size_of::>>(), size_of::<&u8>()); - } + assert_eq!(size_of::>>(), size_of::<&u8>()); } #[test] @@ -1731,7 +1938,6 @@ mod std_tests { assert_eq!(v, &[(), ()]); } -/* TODO: support inclusive ranges #[test] fn test_drain_inclusive_range() { let mut v = thin_vec!['a', 'b', 'c', 'd', 'e']; @@ -1761,6 +1967,7 @@ mod std_tests { } #[test] + #[cfg(not(feature = "gecko-ffi"))] fn test_drain_max_vec_size() { let mut v = ThinVec::<()>::with_capacity(usize::max_value()); unsafe { v.set_len(usize::max_value()); } @@ -1781,7 +1988,6 @@ mod std_tests { let mut v = thin_vec![1, 2, 3, 4, 5]; v.drain(5..=5); } -*/ /* TODO: implement splice? #[test] @@ -2187,7 +2393,7 @@ mod std_tests { assert!(v.capacity() >= 33) } -/* TODO: implement try_reserve +/* TODO: implement try_reserve #[test] fn test_try_reserve() { --- thunderbird-78.9.0/toolkit/components/cascade_bloom_filter/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:36:12.000000000 +0100 +++ thunderbird-78.9.0/toolkit/components/cascade_bloom_filter/Cargo.toml 2021-03-22 11:37:44.287130273 +0100 @@ -8,5 +8,5 @@ nserror = { path = "../../../xpcom/rust/ nsstring = { path = "../../../xpcom/rust/nsstring" } rental = "0.5.5" rust_cascade = "0.6.0" -thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } xpcom = { path = "../../../xpcom/rust/xpcom" } --- thunderbird-78.9.0/toolkit/components/extensions/storage/webext_storage_bridge/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:36:28.000000000 +0100 +++ thunderbird-78.9.0/toolkit/components/extensions/storage/webext_storage_bridge/Cargo.toml 2021-03-22 11:37:44.288130270 +0100 @@ -13,7 +13,7 @@ moz_task = { path = "../../../../../xpco nserror = { path = "../../../../../xpcom/rust/nserror" } nsstring = { path = "../../../../../xpcom/rust/nsstring" } once_cell = "1" -thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } xpcom = { path = "../../../../../xpcom/rust/xpcom" } serde = "1" serde_json = "1" --- thunderbird-78.9.0/toolkit/components/kvstore/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:36:33.000000000 +0100 +++ thunderbird-78.9.0/toolkit/components/kvstore/Cargo.toml 2021-03-22 11:37:44.289130267 +0100 @@ -18,7 +18,7 @@ rkv = "0.10.2" storage_variant = { path = "../../../storage/variant" } xpcom = { path = "../../../xpcom/rust/xpcom" } tempfile = "3" -thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } # Get rid of failure's dependency on backtrace. Eventually # backtrace will move into Rust core, but we don't need it here. --- thunderbird-78.9.0/toolkit/components/places/bookmark_sync/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:36:25.000000000 +0100 +++ thunderbird-78.9.0/toolkit/components/places/bookmark_sync/Cargo.toml 2021-03-22 11:37:44.289130267 +0100 @@ -19,5 +19,5 @@ url = "2.0" xpcom = { path = "../../../../xpcom/rust/xpcom" } [dependencies.thin-vec] -version = "0.1.0" +version = "0.2.1" features = ["gecko-ffi"] --- thunderbird-78.9.0/tools/profiler/rust-helper/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:36:33.000000000 +0100 +++ thunderbird-78.9.0/tools/profiler/rust-helper/Cargo.toml 2021-03-22 11:37:44.290130265 +0100 @@ -23,7 +23,7 @@ features = ["endian_fd", "elf32", "elf64 default-features = false [dependencies.thin-vec] -version = "0.1.0" +version = "0.2.1" features = ["gecko-ffi"] [features] --- thunderbird-78.9.0/xpcom/rust/xpcom/Cargo.toml.D87019-thin-vec-big-endian.diff 2021-03-19 22:36:33.000000000 +0100 +++ thunderbird-78.9.0/xpcom/rust/xpcom/Cargo.toml 2021-03-22 11:37:44.291130262 +0100 @@ -9,4 +9,4 @@ nsstring = { path = "../nsstring" } nserror = { path = "../nserror" } threadbound = "0.1" xpcom_macros = { path = "xpcom_macros" } -thin-vec = { version = "0.1.0", features = ["gecko-ffi"] } +thin-vec = { version = "0.2.1", features = ["gecko-ffi"] }