@@ -462,8 +462,52 @@ impl<H, T: Clone> HeaderVec<H, T> {
462462
463463#[ cfg( feature = "atomic_append" ) ]
464464/// The atomic append API is only enabled when the `atomic_append` feature flag is set (which
465- /// is the default).
465+ /// is the default). The [`push_atomic()`] or [`extend_from_slice_atomic()`] methods then
466+ /// become available and some internals using atomic operations.
467+ ///
468+ /// This API implements interior-mutable appending to a shared `HeaderVec`. To other threads
469+ /// the appended elements are either not seen or all seen at once. Without additional
470+ /// synchronization these appends are racy but memory safe. The intention behind this API is to
471+ /// provide facilities for building other container abstractions the benefit from the shared
472+ /// non blocking nature while being unaffected from the racy semantics or provide synchronization
473+ /// on their own (Eg: reference counted data, interners, streaming parsers, etc). Since the
474+ /// `HeaderVec` is a shared object and we have only a `&self`, it can not be reallocated and moved,
475+ /// therefore appending can only be done within the reserved capacity.
476+ ///
477+ /// # Safety
478+ ///
479+ /// Only one single thread must try to [`push_atomic()`] or [`extend_from_slice_atomic()`] the
480+ /// `HeaderVec` at at time using the atomic append API's. The actual implementations of this
481+ /// restriction is left to the caller. This can be done by mutexes or guard objects. Or
482+ /// simply by staying single threaded or ensuring somehow else that there is only a single
483+ /// thread using the atomic_appending API.
466484impl < H , T > HeaderVec < H , T > {
485+ /// Atomically adds an item to the end of the list without reallocation.
486+ ///
487+ /// # Errors
488+ ///
489+ /// If the vector is full, the item is returned.
490+ ///
491+ /// # Safety
492+ ///
493+ /// There must be only one thread calling this method at any time. Synchronization has to
494+ /// be provided by the user.
495+ pub unsafe fn push_atomic ( & self , item : T ) -> Result < ( ) , T > {
496+ // relaxed is good enough here because this should be the only thread calling this method.
497+ let len = self . len_atomic_relaxed ( ) ;
498+ if len < self . capacity ( ) {
499+ unsafe {
500+ core:: ptr:: write ( self . end_ptr_atomic_mut ( ) , item) ;
501+ } ;
502+ let len_again = self . len_atomic_add_release ( 1 ) ;
503+ // in debug builds we check for races, the chance to catch these are still pretty minimal
504+ debug_assert_eq ! ( len_again, len, "len was updated by another thread" ) ;
505+ Ok ( ( ) )
506+ } else {
507+ Err ( item)
508+ }
509+ }
510+
467511 /// Get the length of the vector with `Ordering::Acquire`. This ensures that the length is
468512 /// properly synchronized after it got atomically updated.
469513 #[ inline( always) ]
@@ -505,32 +549,6 @@ impl<H, T> HeaderVec<H, T> {
505549 fn end_ptr_atomic_mut ( & self ) -> * mut T {
506550 unsafe { self . start_ptr ( ) . add ( self . len_atomic_acquire ( ) ) as * mut T }
507551 }
508-
509- /// Atomically adds an item to the end of the list without reallocation.
510- ///
511- /// # Errors
512- ///
513- /// If the vector is full, the item is returned.
514- ///
515- /// # Safety
516- ///
517- /// There must be only one thread calling this method at any time. Synchronization has to
518- /// be provided by the user.
519- pub unsafe fn push_atomic ( & self , item : T ) -> Result < ( ) , T > {
520- // relaxed is good enough here because this should be the only thread calling this method.
521- let len = self . len_atomic_relaxed ( ) ;
522- if len < self . capacity ( ) {
523- unsafe {
524- core:: ptr:: write ( self . end_ptr_atomic_mut ( ) , item) ;
525- } ;
526- let len_again = self . len_atomic_add_release ( 1 ) ;
527- // in debug builds we check for races, the chance to catch these are still pretty minimal
528- debug_assert_eq ! ( len_again, len, "len was updated by another thread" ) ;
529- Ok ( ( ) )
530- } else {
531- Err ( item)
532- }
533- }
534552}
535553
536554#[ cfg( feature = "atomic_append" ) ]
0 commit comments