Skip to content

Commit d6dec5f

Browse files
committed
chore: Move suffix code into own file
1 parent 9c29483 commit d6dec5f

File tree

2 files changed

+304
-261
lines changed

2 files changed

+304
-261
lines changed

crates/stackable-operator/src/quantity/mod.rs

Lines changed: 18 additions & 261 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::{
22
fmt::{Display, Write},
33
num::ParseFloatError,
4-
ops::Deref,
54
str::FromStr,
65
};
76

@@ -12,9 +11,11 @@ mod cpu;
1211
mod macros;
1312
mod memory;
1413
mod ops;
14+
mod suffix;
1515

1616
pub use cpu::*;
1717
pub use memory::*;
18+
pub use suffix::*;
1819

1920
#[derive(Debug, PartialEq, Snafu)]
2021
pub enum ParseQuantityError {
@@ -123,8 +124,7 @@ impl TryFrom<&K8sQuantity> for Quantity {
123124
impl Quantity {
124125
/// Optionally scales up or down to the provided `suffix`.
125126
///
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:
128128
///
129129
/// - the suffixes already match
130130
/// - the value is 0
@@ -144,250 +144,11 @@ impl Quantity {
144144
}
145145
}
146146

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-
360147
#[cfg(test)]
361148
mod test {
362149
use super::*;
363150
use rstest::rstest;
364151

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-
391152
#[rstest]
392153
#[case("49041204Ki", Quantity { value: 49041204.0, suffix: Suffix::BinaryMultiple(BinaryMultiple::Kibi) })]
393154
#[case("256Ki", Quantity { value: 256.0, suffix: Suffix::BinaryMultiple(BinaryMultiple::Kibi) })]
@@ -416,10 +177,10 @@ mod test {
416177
}
417178

418179
#[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)) })]
423184
fn decimal_exponent_quantity_from_str_pass(#[case] input: &str, #[case] expected: Quantity) {
424185
let parsed = Quantity::from_str(input).unwrap();
425186
assert_eq!(parsed, expected);
@@ -440,14 +201,13 @@ mod test {
440201
}
441202

442203
#[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")]
446207
fn binary_to_binary_scale_pass(
447208
#[case] input: &str,
448209
#[case] scale_to: BinaryMultiple,
449210
#[case] output: &str,
450-
#[case] _scaled: bool,
451211
) {
452212
let parsed = Quantity::from_str(input)
453213
.unwrap()
@@ -457,13 +217,12 @@ mod test {
457217
}
458218

459219
#[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")]
462222
fn binary_to_decimal_scale_pass(
463223
#[case] input: &str,
464224
#[case] scale_to: DecimalMultiple,
465225
#[case] output: &str,
466-
#[case] _scaled: bool,
467226
) {
468227
let parsed = Quantity::from_str(input)
469228
.unwrap()
@@ -473,14 +232,13 @@ mod test {
473232
}
474233

475234
#[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")]
479238
fn decimal_to_decimal_scale_pass(
480239
#[case] input: &str,
481240
#[case] scale_to: DecimalMultiple,
482241
#[case] output: &str,
483-
#[case] _scaled: bool,
484242
) {
485243
let parsed = Quantity::from_str(input)
486244
.unwrap()
@@ -490,14 +248,13 @@ mod test {
490248
}
491249

492250
#[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")]
496254
fn decimal_exponent_to_decimal_exponent_scale_pass(
497255
#[case] input: &str,
498256
#[case] scale_to: DecimalExponent,
499257
#[case] output: &str,
500-
#[case] _scaled: bool,
501258
) {
502259
let parsed = Quantity::from_str(input)
503260
.unwrap()

0 commit comments

Comments
 (0)