pub fn push(&self, value: T) -> &T {let mut item = ManuallyDrop::new(value);loop {let last = self.last.load(Ordering::Acquire);// Both of these are from the same `RoseInner`// SAFETY: Last is always a valid pointer.let length = unsafe { &(*last).length };let capacity = unsafe { (*last).capacity };let index = length.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {if x == capacity {// We need to allocate more.None} else {Some(x + 1)}});if let Ok(len) = index {// SAFETY: last is a valid pointer.// We use AcqRel to ensure that other threads are aware we're writing.unsafe { (*last).writers.fetch_add(1, Ordering::AcqRel) };// `writers` cannot overflow because its always less than or equal to`capacity`.// SAFETY: We now "own" the index, as the index was increased, so we can write to it.unsafe {let out = addr_of_mut!((*last).data).cast::<T>().add(len);out.write(addr_of!(item).cast::<T>().read());let writers = (*last).writers.fetch_sub(1, Ordering::AcqRel) - 1;let _ = (*last).active_index.fetch_update(Ordering::AcqRel,Ordering::Acquire,|x| {// If we are the next write or we are the last writer,// we can set the active index.if x == len || writers == 0 {Some(len + 1)} else {None}},);// SAFETY: last is a valid pointer.return &*out;}}let new = Self::alloc(capacity * 2);// SAFETY: We just created the pointer, so we can do whatever we want with it.let refer = unsafe {let new = new.as_ptr();addr_of_mut!((*new).next).write(last);addr_of_mut!((*new).length).write(AtomicUsize::new(1));addr_of_mut!((*new).capacity).write(capacity * 2);addr_of_mut!((*new).writers).write(AtomicUsize::new(0));addr_of_mut!((*new).active_index).write(AtomicUsize::new(1));let out = addr_of_mut!((*new).data).cast::<T>();out.write(addr_of_mut!(item).cast::<T>().read());&*out};let success = self.last.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {if x == last {Some(new.as_ptr())} else {// Somebody changed our pointer.None}});if success.is_ok() {return refer;}// Another thread updated the pointer before us.// SAFETY: We just created the pointer via alloc, so we can deallocate it.unsafe {dealloc(new.as_ptr().cast::<u8>(), Self::layout(capacity * 2));};}}
Click on the green to move the box
(This uses no JS)