1
1
use std:: {
2
2
fmt:: { Display , Write } ,
3
3
num:: ParseFloatError ,
4
- ops:: Deref ,
5
4
str:: FromStr ,
6
5
} ;
7
6
@@ -12,9 +11,11 @@ mod cpu;
12
11
mod macros;
13
12
mod memory;
14
13
mod ops;
14
+ mod suffix;
15
15
16
16
pub use cpu:: * ;
17
17
pub use memory:: * ;
18
+ pub use suffix:: * ;
18
19
19
20
#[ derive( Debug , PartialEq , Snafu ) ]
20
21
pub enum ParseQuantityError {
@@ -123,8 +124,7 @@ impl TryFrom<&K8sQuantity> for Quantity {
123
124
impl Quantity {
124
125
/// Optionally scales up or down to the provided `suffix`.
125
126
///
126
- /// This function returns a value pair which contains an optional [`Quantity`] and a bool
127
- /// indicating if the function performed any scaling. It returns `false` in the following cases:
127
+ /// No scaling is performed in the following cases:
128
128
///
129
129
/// - the suffixes already match
130
130
/// - the value is 0
@@ -144,250 +144,11 @@ impl Quantity {
144
144
}
145
145
}
146
146
147
- #[ derive( Debug , PartialEq , Snafu ) ]
148
- #[ snafu( display( "failed to parse {input:?} as quantity suffix" ) ) ]
149
- pub struct ParseSuffixError {
150
- input : String ,
151
- }
152
-
153
- #[ derive( Clone , Copy , Debug , PartialEq , PartialOrd ) ]
154
- pub enum Suffix {
155
- DecimalMultiple ( DecimalMultiple ) ,
156
- BinaryMultiple ( BinaryMultiple ) ,
157
- DecimalExponent ( DecimalExponent ) ,
158
- }
159
-
160
- impl FromStr for Suffix {
161
- type Err = ParseSuffixError ;
162
-
163
- fn from_str ( input : & str ) -> Result < Self , Self :: Err > {
164
- if let Ok ( binary_si) = BinaryMultiple :: from_str ( input) {
165
- return Ok ( Self :: BinaryMultiple ( binary_si) ) ;
166
- }
167
-
168
- if let Ok ( decimal_si) = DecimalMultiple :: from_str ( input) {
169
- return Ok ( Self :: DecimalMultiple ( decimal_si) ) ;
170
- }
171
-
172
- if input. starts_with ( [ 'e' , 'E' ] ) {
173
- if let Ok ( decimal_exponent) = f64:: from_str ( & input[ 1 ..] ) {
174
- return Ok ( Self :: DecimalExponent ( DecimalExponent ( decimal_exponent) ) ) ;
175
- }
176
- }
177
-
178
- ParseSuffixSnafu { input } . fail ( )
179
- }
180
- }
181
-
182
- impl Display for Suffix {
183
- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
184
- match self {
185
- Suffix :: DecimalMultiple ( decimal) => write ! ( f, "{decimal}" ) ,
186
- Suffix :: BinaryMultiple ( binary) => write ! ( f, "{binary}" ) ,
187
- Suffix :: DecimalExponent ( float) => write ! ( f, "e{float}" ) ,
188
- }
189
- }
190
- }
191
-
192
- impl Suffix {
193
- pub fn factor ( & self ) -> f64 {
194
- match self {
195
- Suffix :: DecimalMultiple ( s) => s. factor ( ) ,
196
- Suffix :: BinaryMultiple ( s) => s. factor ( ) ,
197
- Suffix :: DecimalExponent ( s) => s. factor ( ) ,
198
- }
199
- }
200
- }
201
-
202
- /// Supported byte-multiples based on powers of 2.
203
- ///
204
- /// These units are defined in IEC 80000-13 and are supported by other standards bodies like NIST.
205
- /// The following list contains examples using the official units which Kubernetes adopted with
206
- /// slight changes (mentioned in parentheses).
207
- ///
208
- /// ```plain
209
- /// - 1024^1, KiB (Ki), Kibibyte
210
- /// - 1024^2, MiB (Mi), Mebibyte
211
- /// - 1024^3, GiB (Gi), Gibibyte
212
- /// - 1024^4, TiB (Ti), Tebibyte
213
- /// - 1024^5, PiB (Pi), Pebibyte
214
- /// - 1024^6, EiB (Ei), Exbibyte
215
- /// ```
216
- ///
217
- /// All units bigger than Exbibyte are not a valid suffix according to the [Kubernetes serialization
218
- /// format][k8s-serialization-format].
219
- ///
220
- /// ### See
221
- ///
222
- /// - <https://en.wikipedia.org/wiki/Byte#Multiple-byte_units>
223
- /// - <https://physics.nist.gov/cuu/Units/binary.html>
224
- ///
225
- /// [k8s-serialization-format]: https://github.com/kubernetes/apimachinery/blob/8c60292e48e46c4faa1e92acb232ce6adb37512c/pkg/api/resource/quantity.go#L37-L59
226
- #[ derive( Clone , Copy , Debug , PartialEq , PartialOrd , strum:: Display , strum:: EnumString ) ]
227
- pub enum BinaryMultiple {
228
- #[ strum( serialize = "Ki" ) ]
229
- Kibi ,
230
-
231
- #[ strum( serialize = "Mi" ) ]
232
- Mebi ,
233
-
234
- #[ strum( serialize = "Gi" ) ]
235
- Gibi ,
236
-
237
- #[ strum( serialize = "Ti" ) ]
238
- Tebi ,
239
-
240
- #[ strum( serialize = "Pi" ) ]
241
- Pebi ,
242
-
243
- #[ strum( serialize = "Ei" ) ]
244
- Exbi ,
245
- }
246
-
247
- impl BinaryMultiple {
248
- /// Returns the factor based on powers of 2.
249
- pub fn factor ( & self ) -> f64 {
250
- match self {
251
- BinaryMultiple :: Kibi => 2f64 . powi ( 10 ) ,
252
- BinaryMultiple :: Mebi => 2f64 . powi ( 20 ) ,
253
- BinaryMultiple :: Gibi => 2f64 . powi ( 30 ) ,
254
- BinaryMultiple :: Tebi => 2f64 . powi ( 40 ) ,
255
- BinaryMultiple :: Pebi => 2f64 . powi ( 50 ) ,
256
- BinaryMultiple :: Exbi => 2f64 . powi ( 60 ) ,
257
- }
258
- }
259
- }
260
-
261
- /// Supported byte-multiples based on powers of 10.
262
- ///
263
- /// These units are recommended by the International Electrotechnical Commission (IEC). The
264
- /// following list contains examples using the official SI units and the units used by Kubernetes
265
- /// (mentioned in parentheses). Units used by Kubernetes are a shortened version of the SI units.
266
- ///
267
- /// It should also be noted that there is an inconsistency in the format Kubernetes uses. Kilobytes
268
- /// should use 'K' instead of 'k'.
269
- ///
270
- /// ```plain
271
- /// - 1000^-1, (m): millibyte (Kubernetes only)
272
- /// - 1000^ 0, B ( ): byte (no suffix)
273
- /// - 1000^ 1, kB (k): kilobyte
274
- /// - 1000^ 2, MB (M): Megabyte
275
- /// - 1000^ 3, GB (G): Gigabyte
276
- /// - 1000^ 4, TB (T): Terabyte
277
- /// - 1000^ 5, PB (P): Petabyte
278
- /// - 1000^ 6, EB (E): Exabyte
279
- /// ```
280
- ///
281
- /// All units bigger than Exabyte are not a valid suffix according to the [Kubernetes serialization
282
- /// format][k8s-serialization-format].
283
- ///
284
- /// ### See
285
- ///
286
- /// - <https://en.wikipedia.org/wiki/Byte#Multiple-byte_units>
287
- /// - <https://physics.nist.gov/cuu/Units/binary.html>
288
- ///
289
- /// [k8s-serialization-format]: https://github.com/kubernetes/apimachinery/blob/8c60292e48e46c4faa1e92acb232ce6adb37512c/pkg/api/resource/quantity.go#L37-L59
290
- #[ derive( Clone , Copy , Debug , PartialEq , PartialOrd , strum:: Display , strum:: EnumString ) ]
291
- pub enum DecimalMultiple {
292
- #[ strum( serialize = "m" ) ]
293
- Milli ,
294
-
295
- #[ strum( serialize = "" ) ]
296
- Empty ,
297
-
298
- #[ strum( serialize = "k" ) ]
299
- Kilo ,
300
-
301
- #[ strum( serialize = "M" ) ]
302
- Mega ,
303
-
304
- #[ strum( serialize = "G" ) ]
305
- Giga ,
306
-
307
- #[ strum( serialize = "T" ) ]
308
- Tera ,
309
-
310
- #[ strum( serialize = "P" ) ]
311
- Peta ,
312
-
313
- #[ strum( serialize = "E" ) ]
314
- Exa ,
315
- }
316
-
317
- impl DecimalMultiple {
318
- pub fn factor ( & self ) -> f64 {
319
- match self {
320
- DecimalMultiple :: Milli => 10f64 . powi ( -3 ) ,
321
- DecimalMultiple :: Empty => 10f64 . powi ( 0 ) ,
322
- DecimalMultiple :: Kilo => 10f64 . powi ( 3 ) ,
323
- DecimalMultiple :: Mega => 10f64 . powi ( 6 ) ,
324
- DecimalMultiple :: Giga => 10f64 . powi ( 9 ) ,
325
- DecimalMultiple :: Tera => 10f64 . powi ( 12 ) ,
326
- DecimalMultiple :: Peta => 10f64 . powi ( 15 ) ,
327
- DecimalMultiple :: Exa => 10f64 . powi ( 18 ) ,
328
- }
329
- }
330
- }
331
-
332
- /// Scientific (also known as E) notation of numbers.
333
- ///
334
- /// ### See
335
- ///
336
- /// - <https://en.wikipedia.org/wiki/Scientific_notation#E_notation>
337
- #[ derive( Clone , Copy , Debug , PartialEq , PartialOrd ) ]
338
- pub struct DecimalExponent ( f64 ) ;
339
-
340
- impl Deref for DecimalExponent {
341
- type Target = f64 ;
342
-
343
- fn deref ( & self ) -> & Self :: Target {
344
- & self . 0
345
- }
346
- }
347
-
348
- impl Display for DecimalExponent {
349
- fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
350
- write ! ( f, "{}" , self . 0 )
351
- }
352
- }
353
-
354
- impl DecimalExponent {
355
- pub fn factor ( & self ) -> f64 {
356
- 10f64 . powf ( self . 0 )
357
- }
358
- }
359
-
360
147
#[ cfg( test) ]
361
148
mod test {
362
149
use super :: * ;
363
150
use rstest:: rstest;
364
151
365
- #[ rstest]
366
- #[ case( "Ki" , Suffix :: BinaryMultiple ( BinaryMultiple :: Kibi ) ) ]
367
- #[ case( "Mi" , Suffix :: BinaryMultiple ( BinaryMultiple :: Mebi ) ) ]
368
- #[ case( "Gi" , Suffix :: BinaryMultiple ( BinaryMultiple :: Gibi ) ) ]
369
- #[ case( "Ti" , Suffix :: BinaryMultiple ( BinaryMultiple :: Tebi ) ) ]
370
- #[ case( "Pi" , Suffix :: BinaryMultiple ( BinaryMultiple :: Pebi ) ) ]
371
- #[ case( "Ei" , Suffix :: BinaryMultiple ( BinaryMultiple :: Exbi ) ) ]
372
- fn binary_multiple_from_str_pass ( #[ case] input : & str , #[ case] expected : Suffix ) {
373
- let parsed = Suffix :: from_str ( input) . unwrap ( ) ;
374
- assert_eq ! ( parsed, expected) ;
375
- }
376
-
377
- #[ rstest]
378
- #[ case( "m" , Suffix :: DecimalMultiple ( DecimalMultiple :: Milli ) ) ]
379
- #[ case( "" , Suffix :: DecimalMultiple ( DecimalMultiple :: Empty ) ) ]
380
- #[ case( "k" , Suffix :: DecimalMultiple ( DecimalMultiple :: Kilo ) ) ]
381
- #[ case( "M" , Suffix :: DecimalMultiple ( DecimalMultiple :: Mega ) ) ]
382
- #[ case( "G" , Suffix :: DecimalMultiple ( DecimalMultiple :: Giga ) ) ]
383
- #[ case( "T" , Suffix :: DecimalMultiple ( DecimalMultiple :: Tera ) ) ]
384
- #[ case( "P" , Suffix :: DecimalMultiple ( DecimalMultiple :: Peta ) ) ]
385
- #[ case( "E" , Suffix :: DecimalMultiple ( DecimalMultiple :: Exa ) ) ]
386
- fn decimal_multiple_from_str_pass ( #[ case] input : & str , #[ case] expected : Suffix ) {
387
- let parsed = Suffix :: from_str ( input) . unwrap ( ) ;
388
- assert_eq ! ( parsed, expected) ;
389
- }
390
-
391
152
#[ rstest]
392
153
#[ case( "49041204Ki" , Quantity { value: 49041204.0 , suffix: Suffix :: BinaryMultiple ( BinaryMultiple :: Kibi ) } ) ]
393
154
#[ case( "256Ki" , Quantity { value: 256.0 , suffix: Suffix :: BinaryMultiple ( BinaryMultiple :: Kibi ) } ) ]
@@ -416,10 +177,10 @@ mod test {
416
177
}
417
178
418
179
#[ rstest]
419
- #[ case( "1.234e-3.21" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent ( -3.21 ) ) } ) ]
420
- #[ case( "1.234E-3.21" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent ( -3.21 ) ) } ) ]
421
- #[ case( "1.234e3" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent ( 3.0 ) ) } ) ]
422
- #[ case( "1.234E3" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent ( 3.0 ) ) } ) ]
180
+ #[ case( "1.234e-3.21" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent :: from ( -3.21 ) ) } ) ]
181
+ #[ case( "1.234E-3.21" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent :: from ( -3.21 ) ) } ) ]
182
+ #[ case( "1.234e3" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent :: from ( 3.0 ) ) } ) ]
183
+ #[ case( "1.234E3" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent :: from ( 3.0 ) ) } ) ]
423
184
fn decimal_exponent_quantity_from_str_pass ( #[ case] input : & str , #[ case] expected : Quantity ) {
424
185
let parsed = Quantity :: from_str ( input) . unwrap ( ) ;
425
186
assert_eq ! ( parsed, expected) ;
@@ -440,14 +201,13 @@ mod test {
440
201
}
441
202
442
203
#[ rstest]
443
- #[ case( "1Mi" , BinaryMultiple :: Kibi , "1024Ki" , true ) ]
444
- #[ case( "1024Ki" , BinaryMultiple :: Mebi , "1Mi" , true ) ]
445
- #[ case( "1Mi" , BinaryMultiple :: Mebi , "1Mi" , false ) ]
204
+ #[ case( "1Mi" , BinaryMultiple :: Kibi , "1024Ki" ) ]
205
+ #[ case( "1024Ki" , BinaryMultiple :: Mebi , "1Mi" ) ]
206
+ #[ case( "1Mi" , BinaryMultiple :: Mebi , "1Mi" ) ]
446
207
fn binary_to_binary_scale_pass (
447
208
#[ case] input : & str ,
448
209
#[ case] scale_to : BinaryMultiple ,
449
210
#[ case] output : & str ,
450
- #[ case] _scaled : bool ,
451
211
) {
452
212
let parsed = Quantity :: from_str ( input)
453
213
. unwrap ( )
@@ -457,13 +217,12 @@ mod test {
457
217
}
458
218
459
219
#[ rstest]
460
- #[ case( "1Mi" , DecimalMultiple :: Kilo , "1048.576k" , true ) ]
461
- #[ case( "1Mi" , DecimalMultiple :: Mega , "1.048576M" , true ) ]
220
+ #[ case( "1Mi" , DecimalMultiple :: Kilo , "1048.576k" ) ]
221
+ #[ case( "1Mi" , DecimalMultiple :: Mega , "1.048576M" ) ]
462
222
fn binary_to_decimal_scale_pass (
463
223
#[ case] input : & str ,
464
224
#[ case] scale_to : DecimalMultiple ,
465
225
#[ case] output : & str ,
466
- #[ case] _scaled : bool ,
467
226
) {
468
227
let parsed = Quantity :: from_str ( input)
469
228
. unwrap ( )
@@ -473,14 +232,13 @@ mod test {
473
232
}
474
233
475
234
#[ rstest]
476
- #[ case( "1M" , DecimalMultiple :: Kilo , "1000k" , true ) ]
477
- #[ case( "1000k" , DecimalMultiple :: Mega , "1M" , true ) ]
478
- #[ case( "1M" , DecimalMultiple :: Mega , "1M" , false ) ]
235
+ #[ case( "1M" , DecimalMultiple :: Kilo , "1000k" ) ]
236
+ #[ case( "1000k" , DecimalMultiple :: Mega , "1M" ) ]
237
+ #[ case( "1M" , DecimalMultiple :: Mega , "1M" ) ]
479
238
fn decimal_to_decimal_scale_pass (
480
239
#[ case] input : & str ,
481
240
#[ case] scale_to : DecimalMultiple ,
482
241
#[ case] output : & str ,
483
- #[ case] _scaled : bool ,
484
242
) {
485
243
let parsed = Quantity :: from_str ( input)
486
244
. unwrap ( )
@@ -490,14 +248,13 @@ mod test {
490
248
}
491
249
492
250
#[ rstest]
493
- #[ case( "1e3" , DecimalExponent ( 0.0 ) , "1000e0" , true ) ]
494
- #[ case( "1000e0" , DecimalExponent ( 3.0 ) , "1e3" , true ) ]
495
- #[ case( "1e3" , DecimalExponent ( 3.0 ) , "1e3" , false ) ]
251
+ #[ case( "1e3" , DecimalExponent :: from ( 0.0 ) , "1000e0" ) ]
252
+ #[ case( "1000e0" , DecimalExponent :: from ( 3.0 ) , "1e3" ) ]
253
+ #[ case( "1e3" , DecimalExponent :: from ( 3.0 ) , "1e3" ) ]
496
254
fn decimal_exponent_to_decimal_exponent_scale_pass (
497
255
#[ case] input : & str ,
498
256
#[ case] scale_to : DecimalExponent ,
499
257
#[ case] output : & str ,
500
- #[ case] _scaled : bool ,
501
258
) {
502
259
let parsed = Quantity :: from_str ( input)
503
260
. unwrap ( )
0 commit comments