@@ -31,6 +31,20 @@ pub enum ParseQuantityError {
3131 InvalidSuffix { source : ParseSuffixError } ,
3232}
3333
34+ // pub struct CpuQuant(Quantity1<DecimalMultiple>);
35+
36+ // pub struct Quantity1<T>
37+ // where
38+ // T: SuffixTrait,
39+ // {
40+ // value: f64,
41+ // suffix: T,
42+ // }
43+
44+ // pub trait SuffixTrait: FromStr + Default {
45+ // fn factor(&self) -> f64;
46+ // }
47+
3448/// Quantity is a representation of a number with a suffix / format.
3549///
3650/// This type makes it possible to parse Kubernetes quantity strings like '12Ki', '2M, '1.5e2', or
@@ -208,6 +222,28 @@ impl Quantity {
208222 }
209223 }
210224
225+ pub fn scale_to_non_zero ( self ) -> Self {
226+ if !self . value . between ( -1.0 , 1.0 ) {
227+ return self ;
228+ }
229+
230+ let mut this = self ;
231+
232+ while let Some ( suffix) = this. suffix . scale_down ( ) {
233+ this = self . scale_to ( suffix) ;
234+ if this. value . between ( -1.0 , 1.0 ) {
235+ continue ;
236+ } else {
237+ return this;
238+ }
239+ }
240+
241+ Self {
242+ value : 1.0 ,
243+ suffix : this. suffix ,
244+ }
245+ }
246+
211247 /// Either sets the suffix of `self` to `rhs` or scales `rhs` if `self` has a value other than
212248 /// zero.
213249 ///
@@ -228,46 +264,54 @@ impl Quantity {
228264 }
229265}
230266
267+ trait FloatExt : PartialOrd + Sized {
268+ fn between ( self , start : Self , end : Self ) -> bool {
269+ self > start && self < end
270+ }
271+ }
272+
273+ impl FloatExt for f64 { }
274+
231275#[ cfg( test) ]
232276mod test {
233277 use super :: * ;
234278 use rstest:: rstest;
235279
280+ // See https://github.com/kubernetes/apimachinery/blob/3e8e52d6a1259ada73f63c1c7d1fad39d4ba9fb4/pkg/api/resource/quantity_test.go#L276-L287
281+ #[ rustfmt:: skip]
236282 #[ rstest]
237- #[ case( "49041204Ki" , Quantity { value: 49041204.0 , suffix: Suffix :: BinaryMultiple ( BinaryMultiple :: Kibi ) } ) ]
238- #[ case( "256Ki" , Quantity { value: 256.0 , suffix: Suffix :: BinaryMultiple ( BinaryMultiple :: Kibi ) } ) ]
239- #[ case( "1.5Gi" , Quantity { value: 1.5 , suffix: Suffix :: BinaryMultiple ( BinaryMultiple :: Gibi ) } ) ]
240- #[ case( "0.8Ti" , Quantity { value: 0.8 , suffix: Suffix :: BinaryMultiple ( BinaryMultiple :: Tebi ) } ) ]
241- #[ case( "3.2Pi" , Quantity { value: 3.2 , suffix: Suffix :: BinaryMultiple ( BinaryMultiple :: Pebi ) } ) ]
242- #[ case( "0.2Ei" , Quantity { value: 0.2 , suffix: Suffix :: BinaryMultiple ( BinaryMultiple :: Exbi ) } ) ]
243- #[ case( "8Mi" , Quantity { value: 8.0 , suffix: Suffix :: BinaryMultiple ( BinaryMultiple :: Mebi ) } ) ]
244- fn binary_quantity_from_str_pass ( #[ case] input : & str , #[ case] expected : Quantity ) {
283+ #[ case( "0" , 0.0 , Suffix :: DecimalMultiple ( DecimalMultiple :: Empty ) ) ]
284+ #[ case( "0n" , 0.0 , Suffix :: DecimalMultiple ( DecimalMultiple :: Nano ) ) ]
285+ #[ case( "0u" , 0.0 , Suffix :: DecimalMultiple ( DecimalMultiple :: Micro ) ) ]
286+ #[ case( "0m" , 0.0 , Suffix :: DecimalMultiple ( DecimalMultiple :: Milli ) ) ]
287+ #[ case( "0Ki" , 0.0 , Suffix :: BinaryMultiple ( BinaryMultiple :: Kibi ) ) ]
288+ #[ case( "0k" , 0.0 , Suffix :: DecimalMultiple ( DecimalMultiple :: Kilo ) ) ]
289+ #[ case( "0Mi" , 0.0 , Suffix :: BinaryMultiple ( BinaryMultiple :: Mebi ) ) ]
290+ #[ case( "0M" , 0.0 , Suffix :: DecimalMultiple ( DecimalMultiple :: Mega ) ) ]
291+ #[ case( "0Gi" , 0.0 , Suffix :: BinaryMultiple ( BinaryMultiple :: Gibi ) ) ]
292+ #[ case( "0G" , 0.0 , Suffix :: DecimalMultiple ( DecimalMultiple :: Giga ) ) ]
293+ #[ case( "0Ti" , 0.0 , Suffix :: BinaryMultiple ( BinaryMultiple :: Tebi ) ) ]
294+ #[ case( "0T" , 0.0 , Suffix :: DecimalMultiple ( DecimalMultiple :: Tera ) ) ]
295+ #[ case( "0Pi" , 0.0 , Suffix :: BinaryMultiple ( BinaryMultiple :: Pebi ) ) ]
296+ #[ case( "0P" , 0.0 , Suffix :: DecimalMultiple ( DecimalMultiple :: Peta ) ) ]
297+ #[ case( "0Ei" , 0.0 , Suffix :: BinaryMultiple ( BinaryMultiple :: Exbi ) ) ]
298+ #[ case( "0E" , 0.0 , Suffix :: DecimalMultiple ( DecimalMultiple :: Exa ) ) ]
299+ fn parse_zero_quantity ( #[ case] input : & str , #[ case] expected_value : f64 , #[ case] expected_suffix : Suffix ) {
245300 let parsed = Quantity :: from_str ( input) . unwrap ( ) ;
246- assert_eq ! ( parsed, expected) ;
247- }
248301
249- #[ rstest]
250- #[ case( "49041204k" , Quantity { value: 49041204.0 , suffix: Suffix :: DecimalMultiple ( DecimalMultiple :: Kilo ) } ) ]
251- #[ case( "256k" , Quantity { value: 256.0 , suffix: Suffix :: DecimalMultiple ( DecimalMultiple :: Kilo ) } ) ]
252- #[ case( "1.5G" , Quantity { value: 1.5 , suffix: Suffix :: DecimalMultiple ( DecimalMultiple :: Giga ) } ) ]
253- #[ case( "0.8T" , Quantity { value: 0.8 , suffix: Suffix :: DecimalMultiple ( DecimalMultiple :: Tera ) } ) ]
254- #[ case( "3.2P" , Quantity { value: 3.2 , suffix: Suffix :: DecimalMultiple ( DecimalMultiple :: Peta ) } ) ]
255- #[ case( "0.2E" , Quantity { value: 0.2 , suffix: Suffix :: DecimalMultiple ( DecimalMultiple :: Exa ) } ) ]
256- #[ case( "4m" , Quantity { value: 4.0 , suffix: Suffix :: DecimalMultiple ( DecimalMultiple :: Milli ) } ) ]
257- #[ case( "8M" , Quantity { value: 8.0 , suffix: Suffix :: DecimalMultiple ( DecimalMultiple :: Mega ) } ) ]
258- fn decimal_quantity_from_str_pass ( #[ case] input : & str , #[ case] expected : Quantity ) {
259- let parsed = Quantity :: from_str ( input) . unwrap ( ) ;
260- assert_eq ! ( parsed, expected) ;
302+ assert_eq ! ( parsed. suffix, expected_suffix) ;
303+ assert_eq ! ( parsed. value, expected_value) ;
261304 }
262305
306+ // See https://github.com/kubernetes/apimachinery/blob/3e8e52d6a1259ada73f63c1c7d1fad39d4ba9fb4/pkg/api/resource/quantity_test.go#L289
307+ #[ rustfmt:: skip]
263308 #[ rstest]
264- #[ case( "1.234e-3.21" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent :: from( -3.21 ) ) } ) ]
265- #[ case( "1.234E-3.21" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent :: from( -3.21 ) ) } ) ]
266- #[ case( "1.234e3" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent :: from( 3.0 ) ) } ) ]
267- #[ case( "1.234E3" , Quantity { value: 1.234 , suffix: Suffix :: DecimalExponent ( DecimalExponent :: from( 3.0 ) ) } ) ]
268- fn decimal_exponent_quantity_from_str_pass ( #[ case] input : & str , #[ case] expected : Quantity ) {
309+ #[ case( "12.34" , 12.34 ) ]
310+ #[ case( "12" , 12.0 ) ]
311+ #[ case( "1" , 1.0 ) ]
312+ fn parse_quantity_without_suffix ( #[ case] input : & str , #[ case] expected_value : f64 ) {
269313 let parsed = Quantity :: from_str ( input) . unwrap ( ) ;
270- assert_eq ! ( parsed, expected ) ;
314+ assert_eq ! ( parsed. value , expected_value ) ;
271315 }
272316
273317 #[ rstest]
0 commit comments