|
| 1 | +{-# LANGUAGE DeriveGeneric #-} |
| 2 | +{-# LANGUAGE DeriveAnyClass #-} |
| 3 | + |
| 4 | +module Kubernetes.OpenAPI.CustomTypes where |
| 5 | + |
| 6 | +import Data.Aeson (FromJSON, ToJSON) |
| 7 | +import Data.Data (Typeable) |
| 8 | +import Data.Text (Text) |
| 9 | + |
| 10 | +import GHC.Generics |
| 11 | + |
| 12 | +{- | `IntOrString` |
| 13 | + IntOrString is a type that can hold an int32 or a string. When used |
| 14 | + in JSON or YAML marshalling and unmarshalling, it produces or consumes |
| 15 | + the inner type. This allows you to have, for example, a JSON field |
| 16 | + that can accept a name or number. |
| 17 | +-} |
| 18 | +data IntOrString |
| 19 | + = IntOrStringS Text |
| 20 | + | IntOrStringI Int |
| 21 | + deriving (Show, Eq, ToJSON, FromJSON, Typeable, Generic) |
| 22 | + |
| 23 | +{- | `Quantity` is a fixed-point representation of a number. |
| 24 | + |
| 25 | + It provides convenient marshaling/unmarshaling in JSON and YAML, in |
| 26 | + addition to String() and Int64() accessors. |
| 27 | + |
| 28 | + The serialization format is: |
| 29 | + |
| 30 | + @ |
| 31 | + \<quantity\> ::= \<signedNumber\>\<suffix\> |
| 32 | + (Note that \<suffix\> may be empty, from the \"\" case in \<decimalSI\>.) |
| 33 | + \<digit\> ::= 0 | 1 | ... | 9 |
| 34 | + \<digits\> ::= \<digit\> | \<digit\>\<digits\> |
| 35 | + \<number\> ::= \<digits\> | \<digits\>.\<digits\> | \<digits\>. | .\<digits\> |
| 36 | + \<sign\> ::= \"+\" | \"-\" \<signedNumber\> ::= \<number\> | \<sign\>\<number\> |
| 37 | + \<suffix\> ::= \<binarySI\> | \<decimalExponent\> | \<decimalSI\> |
| 38 | + \<binarySI\> ::= Ki | Mi | Gi | Ti | Pi | Ei |
| 39 | + (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) |
| 40 | + \<decimalSI\> ::= m | \"\" | k | M | G | T | P | E |
| 41 | + (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) |
| 42 | + \<decimalExponent\> ::= \"e\" \<signedNumber\> | \"E\" \<signedNumber\> |
| 43 | + @ |
| 44 | + |
| 45 | + No matter which of the three exponent forms is used, no quantity may |
| 46 | + represent a number greater than 2^63-1 in magnitude, nor may it have |
| 47 | + more than 3 decimal places. Numbers larger or more precise will be |
| 48 | + capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be |
| 49 | + extended in the future if we require larger or smaller quantities. |
| 50 | + |
| 51 | + When a Quantity is parsed from a string, it will remember the type of |
| 52 | + suffix it had, and will use the same type again when it is serialized. |
| 53 | + |
| 54 | + Before serializing, Quantity will be put in "canonical form". This |
| 55 | + means that Exponent/suffix will be adjusted up or down (with a |
| 56 | + corresponding increase or decrease in Mantissa) such that: |
| 57 | +
|
| 58 | + - No precision is lost |
| 59 | + - No fractional digits will be emitted |
| 60 | + - The exponent (or suffix) is as large as possible. |
| 61 | +
|
| 62 | + The sign will be omitted unless the number is negative. |
| 63 | + |
| 64 | + Examples: |
| 65 | +
|
| 66 | + - 1.5 will be serialized as "1500m" |
| 67 | + - 1.5Gi will be serialized as "1536Mi" |
| 68 | + |
| 69 | + Note that the quantity will NEVER be internally represented by a |
| 70 | + floating point number. That is the whole point of this exercise. |
| 71 | + |
| 72 | + Non-canonical values will still parse as long as they are well formed, |
| 73 | + but will be re-emitted in their canonical form. (So always use |
| 74 | + canonical form, or don't diff.) |
| 75 | + |
| 76 | + This format is intended to make it difficult to use these numbers |
| 77 | + without writing some sort of special handling code in the hopes that |
| 78 | + that will cause implementors to also use a fixed point implementation. |
| 79 | +-} |
| 80 | +newtype Quantity = Quantity { unQuantity :: Text } |
| 81 | + deriving (Show, Eq, ToJSON, FromJSON, Typeable, Generic) |
0 commit comments