# arvo — roadmap
> Legend: ✅ done · 🚧 in progress · ⬜ planned
**Design rule:** arvo only implements a type when it adds validation, normalisation, or domain semantics that the raw type or an existing well-maintained crate does not already provide.
---
## `contact` feature
| `EmailAddress` | ✅ | normalised to lowercase, regex validated |
| `PhoneNumber` | ✅ | E.164, strips spaces/dashes |
| `CountryCode` | ✅ | ISO 3166-1 alpha-2, normalised to uppercase |
| `PostalAddress` | ✅ | composite: street + city + zip + `CountryCode`; fields validated as non-empty |
| `Website` | ✅ | valid URL, http/https only, normalised |
---
## `identifiers` feature
*`Uuid` and `Ulid` are intentionally omitted — use the `uuid` and `ulid` crates directly.*
| `Slug` | ✅ | lowercase, alphanumeric + hyphens, no leading/trailing hyphens |
| `Ean13` | ✅ | EAN-13 barcode with checksum validation |
| `Ean8` | ✅ | EAN-8 barcode with checksum validation |
| `Isbn13` | ✅ | ISBN-13 with check digit |
| `Isbn10` | ✅ | ISBN-10 with check digit |
| `Issn` | ✅ | ISSN with check digit |
| `Vin` | ✅ | Vehicle Identification Number, 17 chars, checksum validated |
---
## `finance` feature
| `Money` | ✅ | `Decimal` amount + `CurrencyCode`; immutable arithmetic helpers |
| `CurrencyCode` | ✅ | ISO 4217 alpha-3 (EUR, USD, CZK…) |
| `Iban` | ✅ | IBAN with mod-97 checksum |
| `Bic` | ✅ | BIC/SWIFT, 8 or 11 chars |
| `VatNumber` | ✅ | EU VAT number with country-prefix + format validation |
| `Percentage` | ✅ | `f64` in range 0–100 |
| `ExchangeRate` | ✅ | positive `Decimal`, from/to `CurrencyCode` pair |
| `CreditCardNumber` | ✅ | Luhn algorithm validation; masked `Display` (shows only last 4 digits) |
| `CardExpiryDate` | ✅ | MM/YY; rejected if in the past at construction time |
---
## `temporal` feature
*`Date`, `Time`, `DateTime`, and `Duration` are intentionally omitted — `chrono` and the `time` crate cover these. arvo adds types with domain-level semantics on top.*
| `UnixTimestamp` | ✅ | non-negative `i64` seconds since epoch |
| `BirthDate` | ✅ | date in the past, not more than 150 years ago |
| `ExpiryDate` | ✅ | date strictly in the future |
| `TimeRange` | ✅ | start + end `DateTime`; `start < end` enforced |
| `BusinessHours` | ✅ | composite: weekday + open time + close time; open < close |
---
## `geo` feature
| `Latitude` | ✅ | `f64` in range −90.0..=90.0 |
| `Longitude` | ✅ | `f64` in range −180.0..=180.0 |
| `Coordinate` | ✅ | composite: `Latitude` + `Longitude` |
| `BoundingBox` | ✅ | composite: SW `Coordinate` + NE `Coordinate` |
| `TimeZone` | ✅ | IANA timezone name (e.g. `Europe/Prague`) |
| `CountryRegion` | ✅ | ISO 3166-2 subdivision code (e.g. `CZ-PR`) |
---
## `net` feature
| `Url` | ✅ | valid URL, wraps `url` crate |
| `Domain` | ✅ | valid domain name without scheme |
| `IpV4Address` | ✅ | valid IPv4 (e.g. `192.168.1.1`) |
| `IpV6Address` | ✅ | valid IPv6 |
| `IpAddress` | ✅ | enum: `V4(IpV4Address)` \| `V6(IpV6Address)` |
| `Port` | ✅ | `u16` in range 1–65535 |
| `MacAddress` | ✅ | 6-byte MAC, normalised to lowercase colon-separated hex |
| `MimeType` | ✅ | valid MIME type (e.g. `image/png`) |
| `HttpStatusCode` | ✅ | `u16` in range 100–599 |
| `ApiKey` | ✅ | non-empty; masked `Display` shows only last 4 chars |
---
## `measurement` feature
> ⚠️ **Design required before implementation.** Each type carries a unit — but without unit conversion (e.g. `km → m`, `°F → °C`) the unit is just a label. The API design for conversions must be settled first. Tracked in issue [#TODO].
| `Length` | ✅ | non-negative `f64` with unit (mm, cm, m, km, in, ft) |
| `Weight` | ✅ | non-negative `f64` with unit (mg, g, kg, t, oz, lb) |
| `Temperature` | ✅ | `f64` with unit (°C, °F, K); validated against absolute zero |
| `Volume` | ✅ | non-negative `f64` with unit (ml, l, m³, fl oz, gal) |
| `Area` | ✅ | non-negative `f64` with unit (mm², cm², m², km², in², ft², ha) |
| `Speed` | ✅ | non-negative `f64` with unit (m/s, km/h, mph, kn) |
| `Pressure` | ✅ | non-negative `f64` with unit (Pa, kPa, MPa, bar, psi, atm) |
| `Energy` | ✅ | non-negative `f64` with unit (J, kJ, MJ, kWh, cal, kcal) |
| `Power` | ✅ | non-negative `f64` with unit (W, kW, MW, hp) |
| `Frequency` | ✅ | positive `f64` with unit (Hz, kHz, MHz, GHz) |
---
## `primitives` feature
| `NonEmptyString` | ✅ | trimmed, at least 1 non-whitespace char |
| `BoundedString` | ✅ | `BoundedString<const MIN: usize, const MAX: usize>` via const generics |
| `PositiveInt` | ✅ | `i64 > 0` |
| `NonNegativeInt` | ✅ | `i64 >= 0` |
| `PositiveDecimal` | ✅ | `Decimal > 0` |
| `NonNegativeDecimal` | ✅ | `Decimal >= 0` |
| `Probability` | ✅ | `f64` in range 0.0..=1.0 |
| `HexColor` | ✅ | `#RRGGBB` or `#RGB`, normalised to uppercase |
| `Locale` | ✅ | BCP 47 language tag (e.g. `en-US`, `cs-CZ`) |
| `Base64String` | ✅ | valid base64-encoded string |
---
## Summary
| `contact` | 5 | 5 | 0 |
| `identifiers` | 7 | 7 | 0 |
| `finance` | 9 | 9 | 0 |
| `temporal` | 5 | 5 | 0 |
| `geo` | 6 | 6 | 0 |
| `net` | 10 | 10 | 0 |
| `measurement` | 10 | 10 | 0 |
| `primitives` | 10 | 10 | 0 |
| **Total** | **62** | **62** | **0** |