1
1
use std:: fmt:: { Display , Formatter } ;
2
2
3
+ use memchr:: memchr;
3
4
use serde:: { de, Deserialize , Deserializer , Serialize , Serializer } ;
4
5
use std:: str:: FromStr ;
5
6
use thiserror:: Error ;
@@ -12,6 +13,7 @@ use uv_platform_tags::{
12
13
PlatformTag , TagCompatibility , Tags ,
13
14
} ;
14
15
16
+ use crate :: splitter:: MemchrSplitter ;
15
17
use crate :: { BuildTag , BuildTagError } ;
16
18
17
19
#[ derive(
@@ -145,64 +147,66 @@ impl WheelFilename {
145
147
// The wheel filename should contain either five or six entries. If six, then the third
146
148
// entry is the build tag. If five, then the third entry is the Python tag.
147
149
// https://www.python.org/dev/peps/pep-0427/#file-name-convention
148
- let mut parts = stem . split ( '-' ) ;
150
+ let mut splitter = memchr :: Memchr :: new ( b '-', stem . as_bytes ( ) ) ;
149
151
150
- let name = parts
151
- . next ( )
152
- . expect ( "split always yields 1 or more elements" ) ;
153
-
154
- let Some ( version) = parts. next ( ) else {
152
+ let Some ( version) = splitter. next ( ) else {
155
153
return Err ( WheelFilenameError :: InvalidWheelFileName (
156
154
filename. to_string ( ) ,
157
155
"Must have a version" . to_string ( ) ,
158
156
) ) ;
159
157
} ;
160
158
161
- let Some ( build_tag_or_python_tag) = parts . next ( ) else {
159
+ let Some ( build_tag_or_python_tag) = splitter . next ( ) else {
162
160
return Err ( WheelFilenameError :: InvalidWheelFileName (
163
161
filename. to_string ( ) ,
164
162
"Must have a Python tag" . to_string ( ) ,
165
163
) ) ;
166
164
} ;
167
165
168
- let Some ( python_tag_or_abi_tag) = parts . next ( ) else {
166
+ let Some ( python_tag_or_abi_tag) = splitter . next ( ) else {
169
167
return Err ( WheelFilenameError :: InvalidWheelFileName (
170
168
filename. to_string ( ) ,
171
169
"Must have an ABI tag" . to_string ( ) ,
172
170
) ) ;
173
171
} ;
174
172
175
- let Some ( abi_tag_or_platform_tag) = parts . next ( ) else {
173
+ let Some ( abi_tag_or_platform_tag) = splitter . next ( ) else {
176
174
return Err ( WheelFilenameError :: InvalidWheelFileName (
177
175
filename. to_string ( ) ,
178
176
"Must have a platform tag" . to_string ( ) ,
179
177
) ) ;
180
178
} ;
181
179
182
- let ( name, version, build_tag, python_tag, abi_tag, platform_tag) =
183
- if let Some ( platform_tag) = parts . next ( ) {
184
- if parts . next ( ) . is_some ( ) {
180
+ let ( name, version, build_tag, python_tag, abi_tag, platform_tag, is_large ) =
181
+ if let Some ( platform_tag) = splitter . next ( ) {
182
+ if splitter . next ( ) . is_some ( ) {
185
183
return Err ( WheelFilenameError :: InvalidWheelFileName (
186
184
filename. to_string ( ) ,
187
185
"Must have 5 or 6 components, but has more" . to_string ( ) ,
188
186
) ) ;
189
187
}
190
188
(
191
- name,
192
- version,
193
- Some ( build_tag_or_python_tag) ,
194
- python_tag_or_abi_tag,
195
- abi_tag_or_platform_tag,
196
- platform_tag,
189
+ & stem[ ..version] ,
190
+ & stem[ version + 1 ..build_tag_or_python_tag] ,
191
+ Some ( & stem[ build_tag_or_python_tag + 1 ..python_tag_or_abi_tag] ) ,
192
+ & stem[ python_tag_or_abi_tag + 1 ..abi_tag_or_platform_tag] ,
193
+ & stem[ abi_tag_or_platform_tag + 1 ..platform_tag] ,
194
+ & stem[ platform_tag + 1 ..] ,
195
+ // Always take the slow path if a build tag is present.
196
+ true ,
197
197
)
198
198
} else {
199
199
(
200
- name ,
201
- version,
200
+ & stem [ ..version ] ,
201
+ & stem [ version + 1 ..build_tag_or_python_tag ] ,
202
202
None ,
203
- build_tag_or_python_tag,
204
- python_tag_or_abi_tag,
205
- abi_tag_or_platform_tag,
203
+ & stem[ build_tag_or_python_tag + 1 ..python_tag_or_abi_tag] ,
204
+ & stem[ python_tag_or_abi_tag + 1 ..abi_tag_or_platform_tag] ,
205
+ & stem[ abi_tag_or_platform_tag + 1 ..] ,
206
+ // Determine whether any of the tag types contain a period, which would indicate
207
+ // that at least one of the tag types includes multiple tags (which in turn
208
+ // necessitates taking the slow path).
209
+ memchr ( b'.' , stem[ build_tag_or_python_tag..] . as_bytes ( ) ) . is_some ( ) ,
206
210
)
207
211
} ;
208
212
@@ -217,30 +221,23 @@ impl WheelFilename {
217
221
} )
218
222
. transpose ( ) ?;
219
223
220
- let tags = if build_tag. is_some ( )
221
- || python_tag. contains ( '.' )
222
- || abi_tag. contains ( '.' )
223
- || platform_tag. contains ( '.' )
224
- {
224
+ let tags = if is_large {
225
225
WheelTag :: Large {
226
226
large : Box :: new ( WheelTagLarge {
227
227
build_tag,
228
- python_tag : python_tag
229
- . split ( '.' )
228
+ python_tag : MemchrSplitter :: split ( python_tag, b'.' )
230
229
. map ( LanguageTag :: from_str)
231
230
. collect :: < Result < _ , _ > > ( )
232
231
. map_err ( |err| {
233
232
WheelFilenameError :: InvalidLanguageTag ( filename. to_string ( ) , err)
234
233
} ) ?,
235
- abi_tag : abi_tag
236
- . split ( '.' )
234
+ abi_tag : MemchrSplitter :: split ( abi_tag, b'.' )
237
235
. map ( AbiTag :: from_str)
238
236
. collect :: < Result < _ , _ > > ( )
239
237
. map_err ( |err| {
240
238
WheelFilenameError :: InvalidAbiTag ( filename. to_string ( ) , err)
241
239
} ) ?,
242
- platform_tag : platform_tag
243
- . split ( '.' )
240
+ platform_tag : MemchrSplitter :: split ( platform_tag, b'.' )
244
241
. map ( PlatformTag :: from_str)
245
242
. collect :: < Result < _ , _ > > ( )
246
243
. map_err ( |err| {
0 commit comments