1+ use crate :: collections:: TryCow ;
12use crate :: error:: { Result , bail} ;
23use crate :: prelude:: * ;
4+ use alloc:: sync:: Arc ;
5+ use core:: borrow:: Borrow ;
36use core:: hash:: Hash ;
47use semver:: Version ;
58use serde_derive:: { Deserialize , Serialize } ;
@@ -12,16 +15,19 @@ use serde_derive::{Deserialize, Serialize};
1215/// which is currently considered a key feature of WASI's compatibility story.
1316///
1417/// On the outside this looks like a map of `K` to `V`.
15- #[ derive( Clone , Serialize , Deserialize , Debug ) ]
16- pub struct NameMap < K : Clone + Hash + Eq + Ord , V > {
18+ #[ derive( Serialize , Deserialize , Debug ) ]
19+ pub struct NameMap < K , V >
20+ where
21+ K : TryClone + Hash + Eq + Ord ,
22+ {
1723 /// A map of keys to the value that they define.
1824 ///
1925 /// Note that this map is "exact" where the name here is the exact name that
2026 /// was specified when the `insert` was called. This doesn't have any
2127 /// semver-mangling or anything like that.
2228 ///
2329 /// This map is always consulted first during lookups.
24- definitions : IndexMap < K , V > ,
30+ definitions : TryIndexMap < K , V > ,
2531
2632 /// An auxiliary map tracking semver-compatible names. This is a map from
2733 /// "semver compatible alternate name" to a name present in `definitions`
@@ -43,12 +49,81 @@ pub struct NameMap<K: Clone + Hash + Eq + Ord, V> {
4349 ///
4450 /// The `Version` here is tracked to ensure that when multiple versions on
4551 /// one track are defined that only the maximal version here is retained.
46- alternate_lookups : IndexMap < K , ( K , Version ) > ,
52+ alternate_lookups : TryIndexMap < K , ( K , TryVersion ) > ,
53+ }
54+
55+ /// A wrapper around `Version` that implements `TryClone`.
56+ #[ derive( Clone , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
57+ struct TryVersion ( Arc < Version > ) ;
58+
59+ impl TryFrom < Version > for TryVersion {
60+ type Error = OutOfMemory ;
61+
62+ fn try_from ( value : Version ) -> Result < Self , Self :: Error > {
63+ Ok ( Self ( try_new :: < Arc < _ > > ( value) ?) )
64+ }
65+ }
66+
67+ impl TryClone for TryVersion {
68+ #[ inline]
69+ fn try_clone ( & self ) -> Result < Self , OutOfMemory > {
70+ Ok ( Self ( self . 0 . clone ( ) ) )
71+ }
72+ }
73+
74+ impl core:: ops:: Deref for TryVersion {
75+ type Target = Version ;
76+
77+ #[ inline]
78+ fn deref ( & self ) -> & Self :: Target {
79+ & self . 0
80+ }
81+ }
82+
83+ impl Borrow < Version > for TryVersion {
84+ #[ inline]
85+ fn borrow ( & self ) -> & Version {
86+ & self . 0
87+ }
88+ }
89+
90+ impl serde:: Serialize for TryVersion {
91+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
92+ where
93+ S : serde:: Serializer ,
94+ {
95+ self . 0 . serialize ( serializer)
96+ }
97+ }
98+
99+ impl < ' de > serde:: Deserialize < ' de > for TryVersion {
100+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
101+ where
102+ D : serde:: Deserializer < ' de > ,
103+ {
104+ use serde:: de:: Error ;
105+ let v = Version :: deserialize ( deserializer) ?;
106+ let v = try_new :: < Arc < _ > > ( v) . map_err ( |oom| D :: Error :: custom ( oom) ) ?;
107+ Ok ( Self ( v) )
108+ }
109+ }
110+
111+ impl < K , V > TryClone for NameMap < K , V >
112+ where
113+ K : TryClone + Hash + Eq + Ord ,
114+ V : TryClone ,
115+ {
116+ fn try_clone ( & self ) -> Result < Self , OutOfMemory > {
117+ Ok ( Self {
118+ definitions : self . definitions . try_clone ( ) ?,
119+ alternate_lookups : self . alternate_lookups . try_clone ( ) ?,
120+ } )
121+ }
47122}
48123
49124impl < K , V > NameMap < K , V >
50125where
51- K : Clone + Hash + Eq + Ord ,
126+ K : TryClone + Hash + Eq + Ord ,
52127{
53128 /// Inserts the `name` specified into this map.
54129 ///
@@ -64,32 +139,32 @@ where
64139 pub fn insert < I > ( & mut self , name : & str , cx : & mut I , allow_shadowing : bool , item : V ) -> Result < K >
65140 where
66141 I : NameMapIntern < Key = K > ,
142+ I :: BorrowedKey : Hash + Eq ,
67143 {
68144 // Always insert `name` and `item` as an exact definition.
69- let key = cx. intern ( name) ;
70- if let Some ( prev) = self . definitions . insert ( key. clone ( ) , item) {
71- if !allow_shadowing {
72- self . definitions . insert ( key, prev) ;
73- bail ! ( "map entry `{name}` defined twice" )
74- }
145+ let key = cx. intern ( name) ?;
146+ if !allow_shadowing && self . definitions . contains_key ( & key) {
147+ bail ! ( "map entry `{name}` defined twice" )
75148 }
149+ self . definitions . insert ( key. try_to_owned ( ) ?, item) ?;
76150
77151 // If `name` is a semver-looking thing, like `a:b/c@1.0.0`, then also
78152 // insert an entry in the semver-compatible map under a key such as
79153 // `a:b/c@1`.
80154 //
81155 // This key is used during `get` later on.
82156 if let Some ( ( alternate_key, version) ) = alternate_lookup_key ( name) {
83- let alternate_key = cx. intern ( alternate_key) ;
84- if let Some ( ( prev_key, prev_version) ) = self
85- . alternate_lookups
86- . insert ( alternate_key. clone ( ) , ( key. clone ( ) , version. clone ( ) ) )
87- {
157+ let alternate_key = cx. intern ( alternate_key) ?;
158+ let version = TryVersion :: try_from ( version) ?;
159+ if let Some ( ( prev_key, prev_version) ) = self . alternate_lookups . insert (
160+ alternate_key. try_clone ( ) ?,
161+ ( key. try_clone ( ) ?, version. clone ( ) ) ,
162+ ) ? {
88163 // Prefer the latest version, so only do this if we're
89164 // greater than the prior version.
90165 if version < prev_version {
91166 self . alternate_lookups
92- . insert ( alternate_key, ( prev_key, prev_version) ) ;
167+ . insert ( alternate_key, ( prev_key, prev_version) ) ? ;
93168 }
94169 }
95170 }
@@ -105,11 +180,13 @@ where
105180 pub fn get < I > ( & self , name : & str , cx : & I ) -> Option < & V >
106181 where
107182 I : NameMapIntern < Key = K > ,
183+ I :: Key : Borrow < I :: BorrowedKey > ,
184+ I :: BorrowedKey : Hash + Eq ,
108185 {
109186 // First look up an exact match and if that's found return that. This
110187 // enables defining multiple versions in the map and the requested
111188 // version is returned if it matches exactly.
112- let candidate = cx. lookup ( name) . and_then ( |k| self . definitions . get ( & k) ) ;
189+ let candidate = cx. lookup ( name) . and_then ( |k| self . definitions . get ( & * k) ) ;
113190 if let Some ( def) = candidate {
114191 return Some ( def) ;
115192 }
@@ -122,7 +199,7 @@ where
122199 let ( alternate_name, _version) = alternate_lookup_key ( name) ?;
123200 let alternate_key = cx. lookup ( alternate_name) ?;
124201 let ( exact_key, _version) = self . alternate_lookups . get ( & alternate_key) ?;
125- self . definitions . get ( exact_key)
202+ self . definitions . get ( exact_key. borrow ( ) )
126203 }
127204
128205 /// Returns an iterator over inserted values in this map.
@@ -142,7 +219,7 @@ where
142219
143220impl < K , V > Default for NameMap < K , V >
144221where
145- K : Clone + Hash + Eq + Ord ,
222+ K : TryClone + Hash + Eq + Ord ,
146223{
147224 fn default ( ) -> NameMap < K , V > {
148225 NameMap {
@@ -156,29 +233,33 @@ where
156233/// keys to non-strings.
157234pub trait NameMapIntern {
158235 /// The key that this interning context generates.
159- type Key ;
236+ type Key : Borrow < Self :: BorrowedKey > ;
237+
238+ /// The borrowed version of the key type.
239+ type BorrowedKey : ?Sized + TryToOwned < Owned = Self :: Key > ;
160240
161241 /// Inserts `s` into `self` and returns the intern'd key `Self::Key`.
162- fn intern ( & mut self , s : & str ) -> Self :: Key ;
242+ fn intern ( & mut self , s : & str ) -> Result < Self :: Key , OutOfMemory > ;
163243
164244 /// Looks up `s` in `self` returning `Some` if it was found or `None` if
165245 /// it's not present.
166- fn lookup ( & self , s : & str ) -> Option < Self :: Key > ;
246+ fn lookup < ' a > ( & ' a self , s : & ' a str ) -> Option < TryCow < ' a , Self :: BorrowedKey > > ;
167247}
168248
169249/// For use with [`NameMap`] when no interning should happen and instead string
170250/// keys are copied as-is.
171251pub struct NameMapNoIntern ;
172252
173253impl NameMapIntern for NameMapNoIntern {
174- type Key = String ;
254+ type Key = TryString ;
255+ type BorrowedKey = str ;
175256
176- fn intern ( & mut self , s : & str ) -> String {
177- s . to_string ( )
257+ fn intern ( & mut self , s : & str ) -> Result < Self :: Key , OutOfMemory > {
258+ TryString :: try_from ( s )
178259 }
179260
180- fn lookup ( & self , s : & str ) -> Option < String > {
181- Some ( s . to_string ( ) )
261+ fn lookup < ' a > ( & ' a self , s : & ' a str ) -> Option < TryCow < ' a , Self :: BorrowedKey > > {
262+ Some ( TryCow :: Borrowed ( s ) )
182263 }
183264}
184265
0 commit comments