1
1
use crate :: {
2
2
builtins:: { PyStr , PyTypeRef } ,
3
3
common:: lock:: PyRwLock ,
4
- Py , PyRef , PyRefExact ,
4
+ convert:: ToPyObject ,
5
+ Py , PyObject , PyObjectRef , PyRef , PyRefExact ,
6
+ } ;
7
+ use std:: {
8
+ borrow:: { Borrow , ToOwned } ,
9
+ ops:: Deref ,
5
10
} ;
6
- use std:: ops:: Deref ;
7
11
8
12
#[ derive( Debug ) ]
9
13
pub struct StringPool {
@@ -28,24 +32,40 @@ impl Clone for StringPool {
28
32
29
33
impl StringPool {
30
34
#[ inline]
31
- pub unsafe fn intern < S : Internable > ( & self , s : S , typ : PyTypeRef ) -> PyRefExact < PyStr > {
32
- if let Some ( found) = self . inner . read ( ) . get ( s. as_str ( ) ) {
33
- return found. clone ( ) . inner ;
35
+ pub unsafe fn intern < S : Internable > ( & self , s : S , typ : PyTypeRef ) -> & ' static PyStrInterned {
36
+ if let Some ( found) = self . interned ( s. as_ref ( ) ) {
37
+ return found;
38
+ }
39
+
40
+ #[ cold]
41
+ fn miss ( zelf : & StringPool , s : PyRefExact < PyStr > ) -> & ' static PyStrInterned {
42
+ let cache = CachedPyStrRef { inner : s } ;
43
+ let inserted = zelf. inner . write ( ) . insert ( cache. clone ( ) ) ;
44
+ if inserted {
45
+ let interned = unsafe { PyStrInterned :: borrow_cache ( & cache) } ;
46
+ // unsafe { interned.as_object().mark_intern() };
47
+ interned
48
+ } else {
49
+ zelf. inner
50
+ . read ( )
51
+ . get ( cache. as_str ( ) )
52
+ . map ( |cached| unsafe { PyStrInterned :: borrow_cache ( cached) } )
53
+ . expect ( "" )
54
+ }
34
55
}
35
- let cache = CachedPyStrRef {
36
- inner : s. into_pyref ( typ) ,
37
- } ;
38
- let inserted = self . inner . write ( ) . insert ( cache. clone ( ) ) ;
39
- if inserted {
40
- cache. inner
41
- } else {
42
- self . inner
43
- . read ( )
44
- . get ( cache. inner . as_str ( ) )
45
- . unwrap ( )
46
- . clone ( )
47
- . inner
56
+ let str_ref = s. into_pyref_exact ( typ) ;
57
+ miss ( self , str_ref)
58
+ }
59
+
60
+ #[ inline]
61
+ pub fn interned < S : MaybeInterned + ?Sized > ( & self , s : & S ) -> Option < & ' static PyStrInterned > {
62
+ if let Some ( interned) = s. as_interned ( ) {
63
+ return Some ( interned) ;
48
64
}
65
+ self . inner
66
+ . read ( )
67
+ . get ( s. as_ref ( ) )
68
+ . map ( |cached| unsafe { PyStrInterned :: borrow_cache ( cached) } )
49
69
}
50
70
}
51
71
@@ -70,57 +90,178 @@ impl PartialEq for CachedPyStrRef {
70
90
impl Eq for CachedPyStrRef { }
71
91
72
92
impl std:: borrow:: Borrow < str > for CachedPyStrRef {
93
+ #[ inline]
73
94
fn borrow ( & self ) -> & str {
74
95
self . inner . as_str ( )
75
96
}
76
97
}
77
98
99
+ impl AsRef < str > for CachedPyStrRef {
100
+ #[ inline]
101
+ fn as_ref ( & self ) -> & str {
102
+ self . as_str ( )
103
+ }
104
+ }
105
+
106
+ impl CachedPyStrRef {
107
+ #[ inline]
108
+ fn as_str ( & self ) -> & str {
109
+ self . inner . as_str ( )
110
+ }
111
+ }
112
+
113
+ /// The unique reference of interned PyStr
114
+ /// Always intended to be used as a static reference
115
+ pub struct PyStrInterned {
116
+ inner : Py < PyStr > ,
117
+ }
118
+
119
+ impl PyStrInterned {
120
+ /// # Safety
121
+ /// the given cache must be alive while returned reference is alive
122
+ #[ inline]
123
+ unsafe fn borrow_cache ( cache : & CachedPyStrRef ) -> & ' static Self {
124
+ std:: mem:: transmute_copy ( cache)
125
+ }
126
+
127
+ #[ inline]
128
+ fn as_ptr ( & self ) -> * const Py < PyStr > {
129
+ self as * const _ as * const _
130
+ }
131
+
132
+ #[ inline]
133
+ pub fn to_owned ( & ' static self ) -> PyRefExact < PyStr > {
134
+ unsafe { ( * ( & self as * const _ as * const PyRefExact < PyStr > ) ) . clone ( ) }
135
+ }
136
+
137
+ #[ inline]
138
+ pub fn to_str ( & ' static self ) -> PyRef < PyStr > {
139
+ self . to_owned ( ) . into_pyref ( )
140
+ }
141
+
142
+ #[ inline]
143
+ pub fn to_object ( & ' static self ) -> PyObjectRef {
144
+ self . to_str ( ) . into ( )
145
+ }
146
+ }
147
+
148
+ impl Borrow < PyObject > for PyStrInterned {
149
+ #[ inline( always) ]
150
+ fn borrow ( & self ) -> & PyObject {
151
+ self . inner . borrow ( )
152
+ }
153
+ }
154
+
155
+ impl Deref for PyStrInterned {
156
+ type Target = Py < PyStr > ;
157
+ #[ inline( always) ]
158
+ fn deref ( & self ) -> & Self :: Target {
159
+ & self . inner
160
+ }
161
+ }
162
+
163
+ impl std:: hash:: Hash for PyStrInterned {
164
+ #[ inline( always) ]
165
+ fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
166
+ std:: hash:: Hash :: hash ( & ( self as * const _ ) , state)
167
+ }
168
+ }
169
+
170
+ impl PartialEq for PyStrInterned {
171
+ #[ inline( always) ]
172
+ fn eq ( & self , other : & Self ) -> bool {
173
+ std:: ptr:: eq ( self , other)
174
+ }
175
+ }
176
+
177
+ impl Eq for PyStrInterned { }
178
+
179
+ impl AsRef < str > for PyStrInterned {
180
+ #[ inline]
181
+ fn as_ref ( & self ) -> & str {
182
+ self . as_str ( )
183
+ }
184
+ }
185
+
186
+ impl std:: fmt:: Debug for PyStrInterned {
187
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
188
+ std:: fmt:: Debug :: fmt ( self . as_str ( ) , f) ?;
189
+ write ! ( f, "@{:p}" , self . as_ptr( ) )
190
+ }
191
+ }
192
+
193
+ impl std:: fmt:: Display for PyStrInterned {
194
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
195
+ std:: fmt:: Display :: fmt ( self . as_str ( ) , f)
196
+ }
197
+ }
198
+
78
199
mod sealed {
79
- use crate :: { builtins:: PyStr , object:: PyRefExact } ;
200
+ use crate :: {
201
+ builtins:: PyStr ,
202
+ object:: { Py , PyRefExact } ,
203
+ } ;
80
204
81
205
pub trait SealedInternable { }
82
206
83
207
impl SealedInternable for String { }
84
-
85
208
impl SealedInternable for & str { }
86
-
87
209
impl SealedInternable for PyRefExact < PyStr > { }
210
+
211
+ pub trait SealedMaybeInterned { }
212
+
213
+ impl SealedMaybeInterned for str { }
214
+ impl SealedMaybeInterned for PyRefExact < PyStr > { }
215
+ impl SealedMaybeInterned for Py < PyStr > { }
88
216
}
89
217
90
218
/// A sealed marker trait for `DictKey` types that always become an exact instance of `str`
91
- pub trait Internable : sealed:: SealedInternable + AsRef < Self :: Key > {
92
- type Key : crate :: dictdatatype:: DictKey + ?Sized ;
93
- fn as_str ( & self ) -> & str ;
94
- fn into_pyref ( self , str_type : PyTypeRef ) -> PyRefExact < PyStr > ;
219
+ pub trait Internable : sealed:: SealedInternable + ToPyObject + AsRef < Self :: Interned > {
220
+ type Interned : ?Sized + MaybeInterned ;
221
+ fn into_pyref_exact ( self , str_type : PyTypeRef ) -> PyRefExact < PyStr > ;
95
222
}
96
223
97
224
impl Internable for String {
98
- type Key = str ;
99
- fn as_str ( & self ) -> & str {
100
- String :: as_str ( self )
101
- }
102
- fn into_pyref ( self , str_type : PyTypeRef ) -> PyRefExact < PyStr > {
225
+ type Interned = str ;
226
+ #[ inline]
227
+ fn into_pyref_exact ( self , str_type : PyTypeRef ) -> PyRefExact < PyStr > {
103
228
let obj = PyRef :: new_ref ( PyStr :: from ( self ) , str_type, None ) ;
104
229
unsafe { PyRefExact :: new_unchecked ( obj) }
105
230
}
106
231
}
107
232
108
233
impl Internable for & str {
109
- type Key = str ;
110
- fn as_str ( & self ) -> & str {
111
- self
112
- }
113
- fn into_pyref ( self , str_type : PyTypeRef ) -> PyRefExact < PyStr > {
114
- self . to_owned ( ) . into_pyref ( str_type)
234
+ type Interned = str ;
235
+ #[ inline]
236
+ fn into_pyref_exact ( self , str_type : PyTypeRef ) -> PyRefExact < PyStr > {
237
+ self . to_owned ( ) . into_pyref_exact ( str_type)
115
238
}
116
239
}
117
240
118
241
impl Internable for PyRefExact < PyStr > {
119
- type Key = Py < PyStr > ;
120
- fn as_str ( & self ) -> & str {
121
- self . deref ( ) . as_str ( )
122
- }
123
- fn into_pyref ( self , _str_type : PyTypeRef ) -> PyRefExact < PyStr > {
242
+ type Interned = Py < PyStr > ;
243
+ #[ inline]
244
+ fn into_pyref_exact ( self , _str_type : PyTypeRef ) -> PyRefExact < PyStr > {
124
245
self
125
246
}
126
247
}
248
+
249
+ pub trait MaybeInterned :
250
+ AsRef < str > + crate :: dictdatatype:: DictKey + sealed:: SealedMaybeInterned
251
+ {
252
+ fn as_interned ( & self ) -> Option < & ' static PyStrInterned > ;
253
+ }
254
+
255
+ impl MaybeInterned for str {
256
+ #[ inline( always) ]
257
+ fn as_interned ( & self ) -> Option < & ' static PyStrInterned > {
258
+ None
259
+ }
260
+ }
261
+
262
+ impl MaybeInterned for Py < PyStr > {
263
+ #[ inline( always) ]
264
+ fn as_interned ( & self ) -> Option < & ' static PyStrInterned > {
265
+ None
266
+ }
267
+ }
0 commit comments