@@ -475,6 +475,40 @@ where
475475 pub fn values_mut ( & mut self ) -> impl Iterator < Item = & mut V > {
476476 self . iter_mut ( ) . map ( |( _, v) | v)
477477 }
478+
479+ /// Returns an entry for the corresponding key
480+ /// ```
481+ /// use heapless::linear_map;
482+ /// use heapless::LinearMap;
483+ /// let mut map = LinearMap::<_, _, 16>::new();
484+ /// if let linear_map::Entry::Vacant(v) = map.entry("a") {
485+ /// v.insert(1).unwrap();
486+ /// }
487+ /// if let linear_map::Entry::Occupied(mut o) = map.entry("a") {
488+ /// println!("found {}", *o.get()); // Prints 1
489+ /// o.insert(2);
490+ /// }
491+ /// // Prints 2
492+ /// println!("val: {}", *map.get("a").unwrap());
493+ /// ```
494+ pub fn entry ( & mut self , key : K ) -> Entry < ' _ , K , V > {
495+ let idx = self
496+ . keys ( )
497+ . enumerate ( )
498+ . find ( |& ( _, k) | * k. borrow ( ) == key)
499+ . map ( |( idx, _) | idx) ;
500+
501+ match idx {
502+ Some ( idx) => Entry :: Occupied ( OccupiedEntry {
503+ idx,
504+ map : self . as_mut_view ( ) ,
505+ } ) ,
506+ None => Entry :: Vacant ( VacantEntry {
507+ key,
508+ map : self . as_mut_view ( ) ,
509+ } ) ,
510+ }
511+ }
478512}
479513
480514impl < K , V , Q , S : LinearMapStorage < K , V > + ?Sized > ops:: Index < & ' _ Q > for LinearMapInner < K , V , S >
@@ -643,11 +677,111 @@ where
643677{
644678}
645679
680+ /// A view into an entry in the map
681+ pub enum Entry < ' a , K , V > {
682+ /// The entry corresponding to the key `K` exists in the map
683+ Occupied ( OccupiedEntry < ' a , K , V > ) ,
684+ /// The entry corresponding to the key `K` does not exist in the map
685+ Vacant ( VacantEntry < ' a , K , V > ) ,
686+ }
687+
688+ /// An occupied entry which can be manipulated
689+ pub struct OccupiedEntry < ' a , K , V > {
690+ // SAFETY: `idx` must not be modified after construction, and
691+ // the size of `map` must not be changed.
692+ idx : usize ,
693+ map : & ' a mut LinearMapView < K , V > ,
694+ }
695+
696+ impl < ' a , K , V > OccupiedEntry < ' a , K , V >
697+ where
698+ K : Eq ,
699+ {
700+ /// Gets a reference to the key that this entity corresponds to
701+ pub fn key ( & self ) -> & K {
702+ // SAFETY: Valid idx from OccupiedEntry construction
703+ let ( k, _v) = unsafe { self . map . buffer . get_unchecked ( self . idx ) } ;
704+ k
705+ }
706+
707+ /// Removes this entry from the map and yields its corresponding key and value
708+ pub fn remove_entry ( self ) -> ( K , V ) {
709+ // SAFETY: Valid idx from OccupiedEntry construction
710+ unsafe { self . map . buffer . swap_remove_unchecked ( self . idx ) }
711+ }
712+
713+ /// Removes this entry from the map and yields its corresponding key and value
714+ pub fn remove ( self ) -> V {
715+ self . remove_entry ( ) . 1
716+ }
717+
718+ /// Gets a reference to the value associated with this entry
719+ pub fn get ( & self ) -> & V {
720+ // SAFETY: Valid idx from OccupiedEntry construction
721+ let ( _k, v) = unsafe { self . map . buffer . get_unchecked ( self . idx ) } ;
722+ v
723+ }
724+
725+ /// Gets a mutable reference to the value associated with this entry
726+ pub fn get_mut ( & mut self ) -> & mut V {
727+ // SAFETY: Valid idx from OccupiedEntry construction
728+ let ( _k, v) = unsafe { self . map . buffer . get_unchecked_mut ( self . idx ) } ;
729+ v
730+ }
731+
732+ /// Consumes this entry and yields a reference to the underlying value
733+ pub fn into_mut ( self ) -> & ' a mut V {
734+ // SAFETY: Valid idx from OccupiedEntry construction
735+ let ( _k, v) = unsafe { self . map . buffer . get_unchecked_mut ( self . idx ) } ;
736+ v
737+ }
738+
739+ /// Overwrites the underlying map's value with this entry's value
740+ pub fn insert ( self , value : V ) -> V {
741+ // SAFETY: Valid idx from OccupiedEntry construction
742+ let ( _k, v) = unsafe { self . map . buffer . get_unchecked_mut ( self . idx ) } ;
743+ mem:: replace ( v, value)
744+ }
745+ }
746+
747+ /// A view into an empty slot in the underlying map
748+ pub struct VacantEntry < ' a , K , V > {
749+ key : K ,
750+ map : & ' a mut LinearMapView < K , V > ,
751+ }
752+
753+ impl < ' a , K , V > VacantEntry < ' a , K , V >
754+ where
755+ K : Eq ,
756+ {
757+ /// Get the key associated with this entry
758+ pub fn key ( & self ) -> & K {
759+ & self . key
760+ }
761+
762+ /// Consumes this entry to yield to key associated with it
763+ pub fn into_key ( self ) -> K {
764+ self . key
765+ }
766+
767+ /// Inserts this entry into to underlying map, yields a mutable reference to the inserted value.
768+ /// If the map is at capacity the value is returned instead.
769+ pub fn insert ( self , value : V ) -> Result < & ' a mut V , V > {
770+ self . map
771+ . buffer
772+ . push ( ( self . key , value) )
773+ . map_err ( |( _k, v) | v) ?;
774+ let idx = self . map . buffer . len ( ) - 1 ;
775+ let r = & mut self . map . buffer [ idx] ;
776+ Ok ( & mut r. 1 )
777+ }
778+ }
779+
646780#[ cfg( test) ]
647781mod test {
648782 use static_assertions:: assert_not_impl_any;
649783
650- use super :: { LinearMap , LinearMapView } ;
784+ use super :: { Entry , LinearMap , LinearMapView } ;
651785
652786 // Ensure a `LinearMap` containing `!Send` keys stays `!Send` itself.
653787 assert_not_impl_any ! ( LinearMap <* const ( ) , ( ) , 4 >: Send ) ;
@@ -780,4 +914,124 @@ mod test {
780914 assert_eq ! ( map. len( ) , 0 ) ;
781915 assert ! ( map. is_empty( ) ) ;
782916 }
917+
918+ // tests that use this constant take too long to run under miri, specially on CI, with a map of
919+ // this size so make the map smaller when using miri
920+ #[ cfg( not( miri) ) ]
921+ const MAP_SLOTS : usize = 4096 ;
922+ #[ cfg( miri) ]
923+ const MAP_SLOTS : usize = 64 ;
924+ fn almost_filled_map ( ) -> LinearMap < usize , usize , MAP_SLOTS > {
925+ let mut almost_filled = LinearMap :: new ( ) ;
926+ for i in 1 ..MAP_SLOTS {
927+ almost_filled. insert ( i, i) . unwrap ( ) ;
928+ }
929+ almost_filled
930+ }
931+
932+ #[ test]
933+ fn entry_find ( ) {
934+ let key = 0 ;
935+ let value = 0 ;
936+ let mut src = almost_filled_map ( ) ;
937+ let entry = src. entry ( key) ;
938+ match entry {
939+ Entry :: Occupied ( _) => {
940+ panic ! ( "Found entry without inserting" ) ;
941+ }
942+ Entry :: Vacant ( v) => {
943+ assert_eq ! ( & key, v. key( ) ) ;
944+ assert_eq ! ( key, v. into_key( ) ) ;
945+ }
946+ }
947+ src. insert ( key, value) . unwrap ( ) ;
948+ let entry = src. entry ( key) ;
949+ match entry {
950+ Entry :: Occupied ( mut o) => {
951+ assert_eq ! ( & key, o. key( ) ) ;
952+ assert_eq ! ( & value, o. get( ) ) ;
953+ assert_eq ! ( & value, o. get_mut( ) ) ;
954+ assert_eq ! ( & value, o. into_mut( ) ) ;
955+ }
956+ Entry :: Vacant ( _) => {
957+ panic ! ( "Entry not found" ) ;
958+ }
959+ }
960+ }
961+
962+ #[ test]
963+ fn entry_vacant_insert ( ) {
964+ let key = 0 ;
965+ let value = 0 ;
966+ let mut src = almost_filled_map ( ) ;
967+ assert_eq ! ( MAP_SLOTS - 1 , src. len( ) ) ;
968+ let entry = src. entry ( key) ;
969+ match entry {
970+ Entry :: Occupied ( _) => {
971+ panic ! ( "Entry found when empty" ) ;
972+ }
973+ Entry :: Vacant ( v) => {
974+ assert_eq ! ( value, * v. insert( value) . unwrap( ) ) ;
975+ }
976+ } ;
977+ assert_eq ! ( value, * src. get( & key) . unwrap( ) ) ;
978+ }
979+
980+ #[ test]
981+ fn entry_occupied_insert ( ) {
982+ let key = 0 ;
983+ let value = 0 ;
984+ let value2 = 5 ;
985+ let mut src = almost_filled_map ( ) ;
986+ assert_eq ! ( MAP_SLOTS - 1 , src. len( ) ) ;
987+ src. insert ( key, value) . unwrap ( ) ;
988+ let entry = src. entry ( key) ;
989+ match entry {
990+ Entry :: Occupied ( o) => {
991+ assert_eq ! ( value, o. insert( value2) ) ;
992+ }
993+ Entry :: Vacant ( _) => {
994+ panic ! ( "Entry not found" ) ;
995+ }
996+ } ;
997+ assert_eq ! ( value2, * src. get( & key) . unwrap( ) ) ;
998+ }
999+
1000+ #[ test]
1001+ fn entry_remove_entry ( ) {
1002+ let key = 0 ;
1003+ let value = 0 ;
1004+ let mut src = almost_filled_map ( ) ;
1005+ src. insert ( key, value) . unwrap ( ) ;
1006+ assert_eq ! ( MAP_SLOTS , src. len( ) ) ;
1007+ let entry = src. entry ( key) ;
1008+ match entry {
1009+ Entry :: Occupied ( o) => {
1010+ assert_eq ! ( ( key, value) , o. remove_entry( ) ) ;
1011+ }
1012+ Entry :: Vacant ( _) => {
1013+ panic ! ( "Entry not found" )
1014+ }
1015+ } ;
1016+ assert_eq ! ( MAP_SLOTS - 1 , src. len( ) ) ;
1017+ }
1018+
1019+ #[ test]
1020+ fn entry_remove ( ) {
1021+ let key = 0 ;
1022+ let value = 0 ;
1023+ let mut src = almost_filled_map ( ) ;
1024+ src. insert ( key, value) . unwrap ( ) ;
1025+ assert_eq ! ( MAP_SLOTS , src. len( ) ) ;
1026+ let entry = src. entry ( key) ;
1027+ match entry {
1028+ Entry :: Occupied ( o) => {
1029+ assert_eq ! ( value, o. remove( ) ) ;
1030+ }
1031+ Entry :: Vacant ( _) => {
1032+ panic ! ( "Entry not found" ) ;
1033+ }
1034+ } ;
1035+ assert_eq ! ( MAP_SLOTS - 1 , src. len( ) ) ;
1036+ }
7831037}
0 commit comments