commit 4e426dfbaa0bb44e59cd4b896d1a9662522e19a5
parent 5a99e7c85154a3c5d19b5f2e4e80f8c84dde31c8
Author: triesap <tyson@radroots.org>
Date: Mon, 27 Jul 2026 14:01:18 +0000
core: rename public values without crate prefixes
- expose concise canonical core value names
- retain deprecated constructor-compatible consumer aliases
- regenerate DTO and successor source authorities
- verify no-std wasm and hermetic workspace gates
Diffstat:
28 files changed, 678 insertions(+), 678 deletions(-)
diff --git a/crates/core/src/currency.rs b/crates/core/src/currency.rs
@@ -13,9 +13,9 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeErr
#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
#[cfg_attr(feature = "dto-bindgen", dto(as = "string"))]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct RadrootsCoreCurrency([u8; 3]);
+pub struct Currency([u8; 3]);
-impl RadrootsCoreCurrency {
+impl Currency {
#[inline]
pub const fn from_const(bytes: [u8; 3]) -> Result<Self, RadrootsCoreCurrencyParseError> {
if Self::is_ascii_upper(bytes[0])
@@ -46,12 +46,12 @@ impl RadrootsCoreCurrency {
core::str::from_utf8(&self.0).unwrap_or("???")
}
- pub const USD: RadrootsCoreCurrency = RadrootsCoreCurrency(*b"USD");
- pub const EUR: RadrootsCoreCurrency = RadrootsCoreCurrency(*b"EUR");
- pub const GBP: RadrootsCoreCurrency = RadrootsCoreCurrency(*b"GBP");
- pub const JPY: RadrootsCoreCurrency = RadrootsCoreCurrency(*b"JPY");
- pub const CAD: RadrootsCoreCurrency = RadrootsCoreCurrency(*b"CAD");
- pub const AUD: RadrootsCoreCurrency = RadrootsCoreCurrency(*b"AUD");
+ pub const USD: Currency = Currency(*b"USD");
+ pub const EUR: Currency = Currency(*b"EUR");
+ pub const GBP: Currency = Currency(*b"GBP");
+ pub const JPY: Currency = Currency(*b"JPY");
+ pub const CAD: Currency = Currency(*b"CAD");
+ pub const AUD: Currency = Currency(*b"AUD");
#[inline]
pub const fn minor_unit_exponent(&self) -> u32 {
@@ -69,28 +69,26 @@ impl RadrootsCoreCurrency {
}
}
-impl fmt::Debug for RadrootsCoreCurrency {
+impl fmt::Debug for Currency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("RadrootsCoreCurrency")
- .field(&self.as_str())
- .finish()
+ f.debug_tuple("Currency").field(&self.as_str()).finish()
}
}
-impl fmt::Display for RadrootsCoreCurrency {
+impl fmt::Display for Currency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
-impl TryFrom<&str> for RadrootsCoreCurrency {
+impl TryFrom<&str> for Currency {
type Error = RadrootsCoreCurrencyParseError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
s.parse()
}
}
-impl FromStr for RadrootsCoreCurrency {
+impl FromStr for Currency {
type Err = RadrootsCoreCurrencyParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -123,16 +121,19 @@ impl fmt::Display for RadrootsCoreCurrencyParseError {
impl std::error::Error for RadrootsCoreCurrencyParseError {}
#[cfg(feature = "serde")]
-impl Serialize for RadrootsCoreCurrency {
+impl Serialize for Currency {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(self.as_str())
}
}
#[cfg(feature = "serde")]
-impl<'de> Deserialize<'de> for RadrootsCoreCurrency {
+impl<'de> Deserialize<'de> for Currency {
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
let s = String::deserialize(de)?;
s.parse().map_err(D::Error::custom)
}
}
+
+#[deprecated(since = "0.1.0", note = "renamed to `Currency`")]
+pub use self::Currency as RadrootsCoreCurrency;
diff --git a/crates/core/src/decimal.rs b/crates/core/src/decimal.rs
@@ -1,7 +1,7 @@
use core::fmt;
use core::ops::{Add, Div, Mul, Sub};
use core::str::FromStr;
-use rust_decimal::Decimal;
+use rust_decimal::Decimal as RustDecimal;
use rust_decimal::prelude::ToPrimitive;
#[cfg(all(feature = "serde", not(feature = "std")))]
@@ -15,11 +15,11 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeErr
#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
#[cfg_attr(feature = "dto-bindgen", dto(as = "string"))]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-pub struct RadrootsCoreDecimal(pub Decimal);
+pub struct Decimal(pub RustDecimal);
-impl RadrootsCoreDecimal {
- pub const ZERO: Self = Self(Decimal::ZERO);
- pub const ONE: Self = Self(Decimal::ONE);
+impl Decimal {
+ pub const ZERO: Self = Self(RustDecimal::ZERO);
+ pub const ONE: Self = Self(RustDecimal::ONE);
#[inline]
pub fn is_zero(&self) -> bool {
@@ -34,7 +34,7 @@ impl RadrootsCoreDecimal {
self.0.rescale(scale);
}
#[inline]
- pub fn normalize(&self) -> Decimal {
+ pub fn normalize(&self) -> RustDecimal {
self.0.normalize()
}
@@ -45,13 +45,13 @@ impl RadrootsCoreDecimal {
#[inline]
pub fn from_str_exact(s: &str) -> Result<Self, rust_decimal::Error> {
- Decimal::from_str_exact(s).map(Self)
+ RustDecimal::from_str_exact(s).map(Self)
}
#[inline]
pub fn from_f64_display(n: f64) -> Result<Self, rust_decimal::Error> {
let s = format!("{:.17}", n);
- Decimal::from_str(&s).map(Self)
+ RustDecimal::from_str(&s).map(Self)
}
#[inline]
pub fn to_f64_lossy(&self) -> Option<f64> {
@@ -69,87 +69,90 @@ impl RadrootsCoreDecimal {
}
#[cfg(feature = "serde")]
-impl Serialize for RadrootsCoreDecimal {
+impl Serialize for Decimal {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.normalize().to_string())
}
}
#[cfg(feature = "serde")]
-impl<'de> Deserialize<'de> for RadrootsCoreDecimal {
+impl<'de> Deserialize<'de> for Decimal {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
- Decimal::from_str(&s)
- .map(RadrootsCoreDecimal)
+ RustDecimal::from_str(&s)
+ .map(Decimal)
.map_err(D::Error::custom)
}
}
-impl fmt::Display for RadrootsCoreDecimal {
+impl fmt::Display for Decimal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.normalize().to_string())
}
}
-impl From<Decimal> for RadrootsCoreDecimal {
- fn from(d: Decimal) -> Self {
+impl From<RustDecimal> for Decimal {
+ fn from(d: RustDecimal) -> Self {
Self(d)
}
}
-impl From<RadrootsCoreDecimal> for Decimal {
- fn from(d: RadrootsCoreDecimal) -> Self {
+impl From<Decimal> for RustDecimal {
+ fn from(d: Decimal) -> Self {
d.0
}
}
-impl From<u32> for RadrootsCoreDecimal {
+impl From<u32> for Decimal {
fn from(v: u32) -> Self {
- Self(Decimal::from(v))
+ Self(RustDecimal::from(v))
}
}
-impl From<i32> for RadrootsCoreDecimal {
+impl From<i32> for Decimal {
fn from(v: i32) -> Self {
- Self(Decimal::from(v))
+ Self(RustDecimal::from(v))
}
}
-impl From<u64> for RadrootsCoreDecimal {
+impl From<u64> for Decimal {
fn from(v: u64) -> Self {
- Self(Decimal::from(v))
+ Self(RustDecimal::from(v))
}
}
-impl From<i64> for RadrootsCoreDecimal {
+impl From<i64> for Decimal {
fn from(v: i64) -> Self {
- Self(Decimal::from(v))
+ Self(RustDecimal::from(v))
}
}
-impl Add for RadrootsCoreDecimal {
+impl Add for Decimal {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
}
}
-impl Sub for RadrootsCoreDecimal {
+impl Sub for Decimal {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
Self(self.0 - rhs.0)
}
}
-impl Mul for RadrootsCoreDecimal {
+impl Mul for Decimal {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
Self(self.0 * rhs.0)
}
}
-impl Div for RadrootsCoreDecimal {
+impl Div for Decimal {
type Output = Self;
fn div(self, rhs: Self) -> Self {
Self(self.0 / rhs.0)
}
}
-impl FromStr for RadrootsCoreDecimal {
+impl FromStr for Decimal {
type Err = rust_decimal::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
- Decimal::from_str(s).map(RadrootsCoreDecimal)
+ RustDecimal::from_str(s).map(Decimal)
}
}
+
+#[deprecated(since = "0.1.0", note = "renamed to `Decimal`")]
+pub use self::Decimal as RadrootsCoreDecimal;
diff --git a/crates/core/src/discount.rs b/crates/core/src/discount.rs
@@ -23,7 +23,7 @@ pub enum RadrootsCoreDiscountScope {
)]
pub enum RadrootsCoreDiscountThreshold {
BinCount { bin_id: String, min: u32 },
- OrderQuantity { min: crate::RadrootsCoreQuantity },
+ OrderQuantity { min: crate::Quantity },
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -35,8 +35,8 @@ pub enum RadrootsCoreDiscountThreshold {
serde(rename_all = "snake_case", tag = "kind", content = "amount")
)]
pub enum RadrootsCoreDiscountValue {
- MoneyPerBin(crate::RadrootsCoreMoney),
- Percent(crate::RadrootsCorePercent),
+ MoneyPerBin(crate::Money),
+ Percent(crate::Percent),
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
diff --git a/crates/core/src/generated/dto_roots.rs b/crates/core/src/generated/dto_roots.rs
@@ -8,13 +8,11 @@ pub fn dto_bindgen_roots() -> ::std::vec::Vec<::dto_bindgen::export::RootDescrip
::dto_bindgen::export::RootDescriptor::new::<crate::discount::RadrootsCoreDiscountThreshold>(
),
::dto_bindgen::export::RootDescriptor::new::<crate::discount::RadrootsCoreDiscountValue>(),
- ::dto_bindgen::export::RootDescriptor::new::<crate::money::RadrootsCoreMoney>(),
- ::dto_bindgen::export::RootDescriptor::new::<crate::percent::RadrootsCorePercent>(),
- ::dto_bindgen::export::RootDescriptor::new::<crate::quantity::RadrootsCoreQuantity>(),
- ::dto_bindgen::export::RootDescriptor::new::<
- crate::quantity_price::RadrootsCoreQuantityPrice,
- >(),
- ::dto_bindgen::export::RootDescriptor::new::<crate::unit::RadrootsCoreUnit>(),
- ::dto_bindgen::export::RootDescriptor::new::<crate::unit::RadrootsCoreUnitDimension>(),
+ ::dto_bindgen::export::RootDescriptor::new::<crate::money::Money>(),
+ ::dto_bindgen::export::RootDescriptor::new::<crate::percent::Percent>(),
+ ::dto_bindgen::export::RootDescriptor::new::<crate::quantity::Quantity>(),
+ ::dto_bindgen::export::RootDescriptor::new::<crate::quantity_price::QuantityPrice>(),
+ ::dto_bindgen::export::RootDescriptor::new::<crate::unit::Unit>(),
+ ::dto_bindgen::export::RootDescriptor::new::<crate::unit::UnitDimension>(),
]
}
diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs
@@ -17,20 +17,34 @@ pub mod quantity_price;
pub mod serde_ext;
pub mod unit;
-pub use currency::{RadrootsCoreCurrency, RadrootsCoreCurrencyParseError};
-pub use decimal::RadrootsCoreDecimal;
+pub use currency::{Currency, RadrootsCoreCurrencyParseError};
+pub use decimal::Decimal;
pub use discount::{
RadrootsCoreDiscount, RadrootsCoreDiscountScope, RadrootsCoreDiscountThreshold,
RadrootsCoreDiscountValue,
};
-pub use money::{RadrootsCoreMoney, RadrootsCoreMoneyInvariantError};
-pub use percent::{RadrootsCorePercent, RadrootsCorePercentParseError};
-pub use quantity::{RadrootsCoreQuantity, RadrootsCoreQuantityInvariantError};
+pub use money::{Money, RadrootsCoreMoneyInvariantError};
+pub use percent::{Percent, RadrootsCorePercentParseError};
+pub use quantity::{Quantity, RadrootsCoreQuantityInvariantError};
pub use quantity_price::{
- RadrootsCoreQuantityPrice, RadrootsCoreQuantityPriceError, RadrootsCoreQuantityPriceOps,
+ QuantityPrice, RadrootsCoreQuantityPriceError, RadrootsCoreQuantityPriceOps,
};
pub use unit::{
- RadrootsCoreUnit, RadrootsCoreUnitConvertError, RadrootsCoreUnitDimension,
- RadrootsCoreUnitParseError, convert_mass_decimal, convert_unit_decimal, convert_volume_decimal,
- parse_mass_unit, parse_volume_unit,
+ RadrootsCoreUnitConvertError, RadrootsCoreUnitParseError, Unit, convert_mass_decimal,
+ convert_unit_decimal, convert_volume_decimal, parse_mass_unit, parse_volume_unit,
};
+
+#[allow(deprecated)]
+pub use currency::RadrootsCoreCurrency;
+#[allow(deprecated)]
+pub use decimal::RadrootsCoreDecimal;
+#[allow(deprecated)]
+pub use money::RadrootsCoreMoney;
+#[allow(deprecated)]
+pub use percent::RadrootsCorePercent;
+#[allow(deprecated)]
+pub use quantity::RadrootsCoreQuantity;
+#[allow(deprecated)]
+pub use quantity_price::RadrootsCoreQuantityPrice;
+#[allow(deprecated)]
+pub use unit::{RadrootsCoreUnit, RadrootsCoreUnitDimension};
diff --git a/crates/core/src/money.rs b/crates/core/src/money.rs
@@ -7,9 +7,9 @@ use rust_decimal::prelude::ToPrimitive;
#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
#[cfg_attr(feature = "dto-bindgen", dto(export))]
#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsCoreMoney {
- pub amount: crate::RadrootsCoreDecimal,
- pub currency: crate::RadrootsCoreCurrency,
+pub struct Money {
+ pub amount: crate::Decimal,
+ pub currency: crate::Currency,
}
#[non_exhaustive]
@@ -35,16 +35,16 @@ impl fmt::Display for RadrootsCoreMoneyInvariantError {
#[cfg(feature = "std")]
impl std::error::Error for RadrootsCoreMoneyInvariantError {}
-impl RadrootsCoreMoney {
+impl Money {
#[inline]
- pub fn new(amount: crate::RadrootsCoreDecimal, currency: crate::RadrootsCoreCurrency) -> Self {
+ pub fn new(amount: crate::Decimal, currency: crate::Currency) -> Self {
Self { amount, currency }
}
#[inline]
- pub fn zero(currency: crate::RadrootsCoreCurrency) -> Self {
+ pub fn zero(currency: crate::Currency) -> Self {
Self {
- amount: crate::RadrootsCoreDecimal::ZERO,
+ amount: crate::Decimal::ZERO,
currency,
}
}
@@ -97,24 +97,24 @@ impl RadrootsCoreMoney {
}
#[inline]
- pub fn mul_decimal(&self, factor: crate::RadrootsCoreDecimal) -> Self {
+ pub fn mul_decimal(&self, factor: crate::Decimal) -> Self {
Self::new(self.amount * factor, self.currency)
}
#[inline]
- pub fn div_decimal(&self, divisor: crate::RadrootsCoreDecimal) -> Self {
+ pub fn div_decimal(&self, divisor: crate::Decimal) -> Self {
Self::new(self.amount / divisor, self.currency)
}
#[inline]
- pub fn from_minor_units_u64(amount_minor: u64, currency: crate::RadrootsCoreCurrency) -> Self {
+ pub fn from_minor_units_u64(amount_minor: u64, currency: crate::Currency) -> Self {
let e = currency.minor_unit_exponent();
let major = Decimal::from_i128_with_scale(amount_minor as i128, e);
- Self::new(crate::RadrootsCoreDecimal(major), currency)
+ Self::new(crate::Decimal(major), currency)
}
#[inline]
- pub fn from_minor_units_u32(amount_minor: u32, currency: crate::RadrootsCoreCurrency) -> Self {
+ pub fn from_minor_units_u32(amount_minor: u32, currency: crate::Currency) -> Self {
Self::from_minor_units_u64(amount_minor as u64, currency)
}
@@ -175,7 +175,7 @@ impl RadrootsCoreMoney {
}
}
-impl fmt::Display for RadrootsCoreMoney {
+impl fmt::Display for Money {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.amount, self.currency)
}
@@ -183,30 +183,33 @@ impl fmt::Display for RadrootsCoreMoney {
use core::ops::{Div, Mul};
-impl Mul<crate::RadrootsCoreDecimal> for RadrootsCoreMoney {
+impl Mul<crate::Decimal> for Money {
type Output = Self;
- fn mul(self, rhs: crate::RadrootsCoreDecimal) -> Self {
+ fn mul(self, rhs: crate::Decimal) -> Self {
self.mul_decimal(rhs)
}
}
-impl Div<crate::RadrootsCoreDecimal> for RadrootsCoreMoney {
+impl Div<crate::Decimal> for Money {
type Output = Self;
- fn div(self, rhs: crate::RadrootsCoreDecimal) -> Self {
+ fn div(self, rhs: crate::Decimal) -> Self {
self.div_decimal(rhs)
}
}
+#[deprecated(since = "0.1.0", note = "renamed to `Money`")]
+pub use self::Money as RadrootsCoreMoney;
+
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pow10_internal_paths_cover_fallback_branches() {
- assert_eq!(RadrootsCoreMoney::pow10(0), Decimal::ONE);
- assert_eq!(RadrootsCoreMoney::pow10(1), Decimal::from(10u32));
- assert_eq!(RadrootsCoreMoney::pow10(2), Decimal::from(100u32));
- assert_eq!(RadrootsCoreMoney::pow10(3), Decimal::from(1_000u32));
- assert_eq!(RadrootsCoreMoney::pow10(6), Decimal::from(1_000_000u32));
+ assert_eq!(Money::pow10(0), Decimal::ONE);
+ assert_eq!(Money::pow10(1), Decimal::from(10u32));
+ assert_eq!(Money::pow10(2), Decimal::from(100u32));
+ assert_eq!(Money::pow10(3), Decimal::from(1_000u32));
+ assert_eq!(Money::pow10(6), Decimal::from(1_000_000u32));
}
}
diff --git a/crates/core/src/percent.rs b/crates/core/src/percent.rs
@@ -1,64 +1,64 @@
use core::fmt;
use core::str::FromStr;
-use crate::RadrootsCoreDecimal;
-use crate::money::RadrootsCoreMoney;
+use crate::Decimal;
+use crate::money::Money;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
#[cfg_attr(feature = "dto-bindgen", dto(export))]
#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsCorePercent {
+pub struct Percent {
#[cfg_attr(feature = "serde", serde(with = "crate::serde_ext::decimal_str"))]
#[cfg_attr(feature = "dto-bindgen", dto(as = "string"))]
- pub value: RadrootsCoreDecimal,
+ pub value: Decimal,
}
-impl RadrootsCorePercent {
+impl Percent {
#[inline]
- pub fn new(value: RadrootsCoreDecimal) -> Self {
+ pub fn new(value: Decimal) -> Self {
Self { value }
}
#[inline]
- pub fn from_ratio(ratio_0_to_1: RadrootsCoreDecimal) -> Self {
+ pub fn from_ratio(ratio_0_to_1: Decimal) -> Self {
Self {
- value: ratio_0_to_1 * RadrootsCoreDecimal::from(100u32),
+ value: ratio_0_to_1 * Decimal::from(100u32),
}
}
#[inline]
- pub fn to_ratio(&self) -> RadrootsCoreDecimal {
- self.value / RadrootsCoreDecimal::from(100u32)
+ pub fn to_ratio(&self) -> Decimal {
+ self.value / Decimal::from(100u32)
}
#[inline]
- pub fn of_money(&self, base: &RadrootsCoreMoney) -> RadrootsCoreMoney {
+ pub fn of_money(&self, base: &Money) -> Money {
base.mul_decimal(self.to_ratio())
}
#[inline]
- pub fn of_money_quantized(&self, base: &RadrootsCoreMoney) -> RadrootsCoreMoney {
+ pub fn of_money_quantized(&self, base: &Money) -> Money {
base.mul_decimal(self.to_ratio()).quantize_to_currency()
}
}
-impl fmt::Display for RadrootsCorePercent {
+impl fmt::Display for Percent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}%", self.value.normalize())
}
}
-impl FromStr for RadrootsCorePercent {
+impl FromStr for Percent {
type Err = RadrootsCorePercentParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let trimmed = s.trim_end();
let no_pct = trimmed.strip_suffix('%').unwrap_or(trimmed).trim();
let dec = no_pct
- .parse::<RadrootsCoreDecimal>()
+ .parse::<Decimal>()
.map_err(|_| RadrootsCorePercentParseError::InvalidNumber)?;
- Ok(RadrootsCorePercent::new(dec))
+ Ok(Percent::new(dec))
}
}
@@ -78,3 +78,6 @@ impl fmt::Display for RadrootsCorePercentParseError {
#[cfg(feature = "std")]
impl std::error::Error for RadrootsCorePercentParseError {}
+
+#[deprecated(since = "0.1.0", note = "renamed to `Percent`")]
+pub use self::Percent as RadrootsCorePercent;
diff --git a/crates/core/src/quantity.rs b/crates/core/src/quantity.rs
@@ -1,7 +1,7 @@
use core::fmt;
-use crate::RadrootsCoreDecimal;
-use crate::unit::{RadrootsCoreUnit, RadrootsCoreUnitConvertError, convert_unit_decimal};
+use crate::Decimal;
+use crate::unit::{RadrootsCoreUnitConvertError, Unit, convert_unit_decimal};
#[cfg(not(feature = "std"))]
use alloc::string::String;
@@ -12,18 +12,18 @@ use std::string::String;
#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
#[cfg_attr(feature = "dto-bindgen", dto(export))]
#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsCoreQuantity {
+pub struct Quantity {
#[cfg_attr(feature = "serde", serde(with = "crate::serde_ext::decimal_str"))]
#[cfg_attr(feature = "dto-bindgen", dto(as = "string"))]
- pub amount: RadrootsCoreDecimal,
- pub unit: RadrootsCoreUnit,
+ pub amount: Decimal,
+ pub unit: Unit,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub label: Option<String>,
}
-impl RadrootsCoreQuantity {
+impl Quantity {
#[inline]
- pub fn new(amount: RadrootsCoreDecimal, unit: RadrootsCoreUnit) -> Self {
+ pub fn new(amount: Decimal, unit: Unit) -> Self {
Self {
amount,
unit,
@@ -50,9 +50,9 @@ impl RadrootsCoreQuantity {
}
#[inline]
- pub fn zero(unit: RadrootsCoreUnit) -> Self {
+ pub fn zero(unit: Unit) -> Self {
Self {
- amount: RadrootsCoreDecimal::ZERO,
+ amount: Decimal::ZERO,
unit,
label: None,
}
@@ -69,20 +69,17 @@ impl RadrootsCoreQuantity {
}
#[inline]
- pub fn canonical_unit(&self) -> RadrootsCoreUnit {
+ pub fn canonical_unit(&self) -> Unit {
self.unit.canonical_unit()
}
#[inline]
- pub fn try_convert_to(
- &self,
- unit: RadrootsCoreUnit,
- ) -> Result<RadrootsCoreQuantity, RadrootsCoreUnitConvertError> {
+ pub fn try_convert_to(&self, unit: Unit) -> Result<Quantity, RadrootsCoreUnitConvertError> {
if self.unit == unit {
return Ok(self.clone());
}
let amount = convert_unit_decimal(self.amount, self.unit, unit)?;
- Ok(RadrootsCoreQuantity {
+ Ok(Quantity {
amount,
unit,
label: self.label.clone(),
@@ -90,7 +87,7 @@ impl RadrootsCoreQuantity {
}
#[inline]
- pub fn to_canonical(&self) -> Result<RadrootsCoreQuantity, RadrootsCoreUnitConvertError> {
+ pub fn to_canonical(&self) -> Result<Quantity, RadrootsCoreUnitConvertError> {
self.try_convert_to(self.unit.canonical_unit())
}
@@ -109,14 +106,11 @@ impl RadrootsCoreQuantity {
}
#[inline]
- pub fn try_add(
- &self,
- rhs: &RadrootsCoreQuantity,
- ) -> Result<RadrootsCoreQuantity, RadrootsCoreQuantityInvariantError> {
+ pub fn try_add(&self, rhs: &Quantity) -> Result<Quantity, RadrootsCoreQuantityInvariantError> {
if self.unit != rhs.unit {
return Err(RadrootsCoreQuantityInvariantError::UnitMismatch);
}
- Ok(RadrootsCoreQuantity {
+ Ok(Quantity {
amount: self.amount + rhs.amount,
unit: self.unit,
label: self.label.clone(),
@@ -124,23 +118,20 @@ impl RadrootsCoreQuantity {
}
#[inline]
- pub fn try_sub(
- &self,
- rhs: &RadrootsCoreQuantity,
- ) -> Result<RadrootsCoreQuantity, RadrootsCoreQuantityInvariantError> {
+ pub fn try_sub(&self, rhs: &Quantity) -> Result<Quantity, RadrootsCoreQuantityInvariantError> {
if self.unit != rhs.unit {
return Err(RadrootsCoreQuantityInvariantError::UnitMismatch);
}
- Ok(RadrootsCoreQuantity {
+ Ok(Quantity {
amount: self.amount - rhs.amount,
unit: self.unit,
label: self.label.clone(),
})
}
- pub fn checked_add(&self, rhs: &RadrootsCoreQuantity) -> Option<RadrootsCoreQuantity> {
+ pub fn checked_add(&self, rhs: &Quantity) -> Option<Quantity> {
if self.unit == rhs.unit {
- Some(RadrootsCoreQuantity {
+ Some(Quantity {
amount: self.amount + rhs.amount,
unit: self.unit,
label: self.label.clone(),
@@ -150,9 +141,9 @@ impl RadrootsCoreQuantity {
}
}
- pub fn checked_sub(&self, rhs: &RadrootsCoreQuantity) -> Option<RadrootsCoreQuantity> {
+ pub fn checked_sub(&self, rhs: &Quantity) -> Option<Quantity> {
if self.unit == rhs.unit {
- Some(RadrootsCoreQuantity {
+ Some(Quantity {
amount: self.amount - rhs.amount,
unit: self.unit,
label: self.label.clone(),
@@ -163,8 +154,8 @@ impl RadrootsCoreQuantity {
}
#[inline]
- pub fn mul_decimal(&self, factor: RadrootsCoreDecimal) -> RadrootsCoreQuantity {
- RadrootsCoreQuantity {
+ pub fn mul_decimal(&self, factor: Decimal) -> Quantity {
+ Quantity {
amount: self.amount * factor,
unit: self.unit,
label: self.label.clone(),
@@ -172,8 +163,8 @@ impl RadrootsCoreQuantity {
}
#[inline]
- pub fn div_decimal(&self, divisor: RadrootsCoreDecimal) -> RadrootsCoreQuantity {
- RadrootsCoreQuantity {
+ pub fn div_decimal(&self, divisor: Decimal) -> Quantity {
+ Quantity {
amount: self.amount / divisor,
unit: self.unit,
label: self.label.clone(),
@@ -181,7 +172,7 @@ impl RadrootsCoreQuantity {
}
}
-impl fmt::Display for RadrootsCoreQuantity {
+impl fmt::Display for Quantity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.amount.normalize(), self.unit)?;
if let Some(label) = &self.label {
@@ -216,10 +207,10 @@ impl std::error::Error for RadrootsCoreQuantityInvariantError {}
use core::ops::{Div, Mul};
-impl Mul<RadrootsCoreDecimal> for RadrootsCoreQuantity {
- type Output = RadrootsCoreQuantity;
- fn mul(self, rhs: RadrootsCoreDecimal) -> RadrootsCoreQuantity {
- RadrootsCoreQuantity {
+impl Mul<Decimal> for Quantity {
+ type Output = Quantity;
+ fn mul(self, rhs: Decimal) -> Quantity {
+ Quantity {
amount: self.amount * rhs,
unit: self.unit,
label: self.label,
@@ -227,13 +218,16 @@ impl Mul<RadrootsCoreDecimal> for RadrootsCoreQuantity {
}
}
-impl Div<RadrootsCoreDecimal> for RadrootsCoreQuantity {
- type Output = RadrootsCoreQuantity;
- fn div(self, rhs: RadrootsCoreDecimal) -> RadrootsCoreQuantity {
- RadrootsCoreQuantity {
+impl Div<Decimal> for Quantity {
+ type Output = Quantity;
+ fn div(self, rhs: Decimal) -> Quantity {
+ Quantity {
amount: self.amount / rhs,
unit: self.unit,
label: self.label,
}
}
}
+
+#[deprecated(since = "0.1.0", note = "renamed to `Quantity`")]
+pub use self::Quantity as RadrootsCoreQuantity;
diff --git a/crates/core/src/quantity_price.rs b/crates/core/src/quantity_price.rs
@@ -1,60 +1,49 @@
-use crate::{RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCoreQuantity, RadrootsCoreUnit};
+use crate::{Decimal, Money, Quantity, Unit};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
#[cfg_attr(feature = "dto-bindgen", dto(export))]
#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct RadrootsCoreQuantityPrice {
- pub amount: RadrootsCoreMoney,
- pub quantity: RadrootsCoreQuantity,
+pub struct QuantityPrice {
+ pub amount: Money,
+ pub quantity: Quantity,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RadrootsCoreQuantityPriceError {
PerQuantityZero,
- UnitMismatch {
- have: RadrootsCoreUnit,
- want: RadrootsCoreUnit,
- },
- NonConvertibleUnits {
- from: RadrootsCoreUnit,
- to: RadrootsCoreUnit,
- },
+ UnitMismatch { have: Unit, want: Unit },
+ NonConvertibleUnits { from: Unit, to: Unit },
}
pub trait RadrootsCoreQuantityPriceOps {
#[must_use]
- fn cost_for(&self, qty: &RadrootsCoreQuantity) -> RadrootsCoreMoney;
+ fn cost_for(&self, qty: &Quantity) -> Money;
#[must_use]
- fn cost_for_rounded(&self, qty: &RadrootsCoreQuantity) -> RadrootsCoreMoney;
+ fn cost_for_rounded(&self, qty: &Quantity) -> Money;
#[must_use]
- fn cost_for_with_quantized_price(&self, qty: &RadrootsCoreQuantity) -> RadrootsCoreMoney;
+ fn cost_for_with_quantized_price(&self, qty: &Quantity) -> Money;
- fn try_cost_for(
- &self,
- qty: &RadrootsCoreQuantity,
- ) -> Result<RadrootsCoreMoney, RadrootsCoreQuantityPriceError>;
+ fn try_cost_for(&self, qty: &Quantity) -> Result<Money, RadrootsCoreQuantityPriceError>;
- fn try_cost_for_rounded(
- &self,
- qty: &RadrootsCoreQuantity,
- ) -> Result<RadrootsCoreMoney, RadrootsCoreQuantityPriceError>;
+ fn try_cost_for_rounded(&self, qty: &Quantity)
+ -> Result<Money, RadrootsCoreQuantityPriceError>;
}
-impl RadrootsCoreQuantityPrice {
+impl QuantityPrice {
#[inline]
- pub fn new(amount: RadrootsCoreMoney, quantity: RadrootsCoreQuantity) -> Self {
+ pub fn new(amount: Money, quantity: Quantity) -> Self {
Self { amount, quantity }
}
#[inline]
pub fn try_cost_for_amount_in(
&self,
- amount: RadrootsCoreDecimal,
- unit: RadrootsCoreUnit,
- ) -> Result<RadrootsCoreMoney, RadrootsCoreQuantityPriceError> {
+ amount: Decimal,
+ unit: Unit,
+ ) -> Result<Money, RadrootsCoreQuantityPriceError> {
use crate::unit::convert_unit_decimal;
let target = self.quantity.unit;
@@ -70,29 +59,29 @@ impl RadrootsCoreQuantityPrice {
})?
};
- let qty = RadrootsCoreQuantity::new(normalized, target);
+ let qty = Quantity::new(normalized, target);
self.try_cost_for_rounded(&qty)
}
#[inline]
pub fn try_cost_for_quantity_in(
&self,
- qty: &RadrootsCoreQuantity,
- ) -> Result<RadrootsCoreMoney, RadrootsCoreQuantityPriceError> {
+ qty: &Quantity,
+ ) -> Result<Money, RadrootsCoreQuantityPriceError> {
self.try_cost_for_amount_in(qty.amount, qty.unit)
}
#[inline]
pub fn is_price_per_canonical_unit(&self) -> bool {
self.quantity.unit == self.quantity.unit.canonical_unit()
- && self.quantity.amount == RadrootsCoreDecimal::ONE
+ && self.quantity.amount == Decimal::ONE
}
#[inline]
pub fn try_to_unit_price(
&self,
- unit: RadrootsCoreUnit,
- ) -> Result<RadrootsCoreQuantityPrice, RadrootsCoreQuantityPriceError> {
+ unit: Unit,
+ ) -> Result<QuantityPrice, RadrootsCoreQuantityPriceError> {
use crate::unit::convert_unit_decimal;
if self.quantity.amount.is_zero() {
@@ -115,31 +104,31 @@ impl RadrootsCoreQuantityPrice {
}
let amount = self.amount.div_decimal(normalized);
- Ok(RadrootsCoreQuantityPrice {
+ Ok(QuantityPrice {
amount,
- quantity: RadrootsCoreQuantity::new(RadrootsCoreDecimal::ONE, unit),
+ quantity: Quantity::new(Decimal::ONE, unit),
})
}
#[inline]
pub fn try_to_canonical_unit_price(
&self,
- ) -> Result<RadrootsCoreQuantityPrice, RadrootsCoreQuantityPriceError> {
+ ) -> Result<QuantityPrice, RadrootsCoreQuantityPriceError> {
self.try_to_unit_price(self.quantity.unit.canonical_unit())
}
}
-impl RadrootsCoreQuantityPriceOps for RadrootsCoreQuantityPrice {
+impl RadrootsCoreQuantityPriceOps for QuantityPrice {
#[inline]
- fn cost_for(&self, qty: &RadrootsCoreQuantity) -> RadrootsCoreMoney {
+ fn cost_for(&self, qty: &Quantity) -> Money {
if qty.amount.is_zero() {
- return RadrootsCoreMoney::zero(self.amount.currency);
+ return Money::zero(self.amount.currency);
}
if self.quantity.amount.is_zero() {
- return RadrootsCoreMoney::zero(self.amount.currency);
+ return Money::zero(self.amount.currency);
}
if qty.unit != self.quantity.unit {
- return RadrootsCoreMoney::zero(self.amount.currency);
+ return Money::zero(self.amount.currency);
}
let ratio = qty.amount / self.quantity.amount;
@@ -147,30 +136,27 @@ impl RadrootsCoreQuantityPriceOps for RadrootsCoreQuantityPrice {
}
#[inline]
- fn cost_for_rounded(&self, qty: &RadrootsCoreQuantity) -> RadrootsCoreMoney {
+ fn cost_for_rounded(&self, qty: &Quantity) -> Money {
self.cost_for(qty).quantize_to_currency()
}
#[inline]
- fn cost_for_with_quantized_price(&self, qty: &RadrootsCoreQuantity) -> RadrootsCoreMoney {
+ fn cost_for_with_quantized_price(&self, qty: &Quantity) -> Money {
if qty.amount.is_zero() {
- return RadrootsCoreMoney::zero(self.amount.currency);
+ return Money::zero(self.amount.currency);
}
if self.quantity.amount.is_zero() {
- return RadrootsCoreMoney::zero(self.amount.currency);
+ return Money::zero(self.amount.currency);
}
if qty.unit != self.quantity.unit {
- return RadrootsCoreMoney::zero(self.amount.currency);
+ return Money::zero(self.amount.currency);
}
let unit_price_q = self.amount.clone().quantize_to_currency();
unit_price_q.mul_decimal(qty.amount / self.quantity.amount)
}
#[inline]
- fn try_cost_for(
- &self,
- qty: &RadrootsCoreQuantity,
- ) -> Result<RadrootsCoreMoney, RadrootsCoreQuantityPriceError> {
+ fn try_cost_for(&self, qty: &Quantity) -> Result<Money, RadrootsCoreQuantityPriceError> {
if self.quantity.amount.is_zero() {
return Err(RadrootsCoreQuantityPriceError::PerQuantityZero);
}
@@ -187,8 +173,11 @@ impl RadrootsCoreQuantityPriceOps for RadrootsCoreQuantityPrice {
#[inline]
fn try_cost_for_rounded(
&self,
- qty: &RadrootsCoreQuantity,
- ) -> Result<RadrootsCoreMoney, RadrootsCoreQuantityPriceError> {
+ qty: &Quantity,
+ ) -> Result<Money, RadrootsCoreQuantityPriceError> {
Ok(self.try_cost_for(qty)?.quantize_to_currency())
}
}
+
+#[deprecated(since = "0.1.0", note = "renamed to `QuantityPrice`")]
+pub use self::QuantityPrice as RadrootsCoreQuantityPrice;
diff --git a/crates/core/src/serde_ext.rs b/crates/core/src/serde_ext.rs
@@ -7,20 +7,15 @@ use serde::{Deserialize, Deserializer, Serializer, de::Error as DeError};
pub mod decimal_str {
use super::*;
- use crate::RadrootsCoreDecimal;
+ use crate::Decimal;
use core::str::FromStr;
- pub fn serialize<S: Serializer>(
- value: &RadrootsCoreDecimal,
- serializer: S,
- ) -> Result<S::Ok, S::Error> {
+ pub fn serialize<S: Serializer>(value: &Decimal, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&value.normalize().to_string())
}
- pub fn deserialize<'de, D: Deserializer<'de>>(
- deserializer: D,
- ) -> Result<RadrootsCoreDecimal, D::Error> {
+ pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Decimal, D::Error> {
let s = String::deserialize(deserializer)?;
- RadrootsCoreDecimal::from_str(&s).map_err(D::Error::custom)
+ Decimal::from_str(&s).map_err(D::Error::custom)
}
}
diff --git a/crates/core/src/unit.rs b/crates/core/src/unit.rs
@@ -11,13 +11,13 @@ use std::string::String;
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError};
-use crate::RadrootsCoreDecimal;
+use crate::Decimal;
#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))]
#[cfg_attr(feature = "dto-bindgen", dto(export))]
#[cfg_attr(feature = "dto-bindgen", dto(as = "string_enum"))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum RadrootsCoreUnitDimension {
+pub enum UnitDimension {
#[cfg_attr(feature = "dto-bindgen", dto(rename = "count"))]
Count,
#[cfg_attr(feature = "dto-bindgen", dto(rename = "mass"))]
@@ -30,7 +30,7 @@ pub enum RadrootsCoreUnitDimension {
#[cfg_attr(feature = "dto-bindgen", dto(export))]
#[cfg_attr(feature = "dto-bindgen", dto(as = "string_enum"))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum RadrootsCoreUnit {
+pub enum Unit {
#[cfg_attr(feature = "dto-bindgen", dto(rename = "each"))]
Each,
#[cfg_attr(feature = "dto-bindgen", dto(rename = "kg"))]
@@ -47,7 +47,7 @@ pub enum RadrootsCoreUnit {
VolumeMl,
}
-impl RadrootsCoreUnit {
+impl Unit {
#[inline]
pub fn code(&self) -> &'static str {
match self {
@@ -66,22 +66,20 @@ impl RadrootsCoreUnit {
}
#[inline]
- pub fn dimension(&self) -> RadrootsCoreUnitDimension {
+ pub fn dimension(&self) -> UnitDimension {
match self {
- Self::Each => RadrootsCoreUnitDimension::Count,
- Self::MassKg | Self::MassG | Self::MassOz | Self::MassLb => {
- RadrootsCoreUnitDimension::Mass
- }
- Self::VolumeL | Self::VolumeMl => RadrootsCoreUnitDimension::Volume,
+ Self::Each => UnitDimension::Count,
+ Self::MassKg | Self::MassG | Self::MassOz | Self::MassLb => UnitDimension::Mass,
+ Self::VolumeL | Self::VolumeMl => UnitDimension::Volume,
}
}
#[inline]
pub fn canonical_unit(&self) -> Self {
match self.dimension() {
- RadrootsCoreUnitDimension::Count => Self::Each,
- RadrootsCoreUnitDimension::Mass => Self::MassG,
- RadrootsCoreUnitDimension::Volume => Self::VolumeMl,
+ UnitDimension::Count => Self::Each,
+ UnitDimension::Mass => Self::MassG,
+ UnitDimension::Volume => Self::VolumeMl,
}
}
@@ -104,7 +102,7 @@ impl RadrootsCoreUnit {
}
}
-impl fmt::Display for RadrootsCoreUnit {
+impl fmt::Display for Unit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.code())
}
@@ -132,18 +130,9 @@ impl std::error::Error for RadrootsCoreUnitParseError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RadrootsCoreUnitConvertError {
- NotMassUnit {
- from: RadrootsCoreUnit,
- to: RadrootsCoreUnit,
- },
- NotVolumeUnit {
- from: RadrootsCoreUnit,
- to: RadrootsCoreUnit,
- },
- NotConvertibleUnits {
- from: RadrootsCoreUnit,
- to: RadrootsCoreUnit,
- },
+ NotMassUnit { from: Unit, to: Unit },
+ NotVolumeUnit { from: Unit, to: Unit },
+ NotConvertibleUnits { from: Unit, to: Unit },
}
impl fmt::Display for RadrootsCoreUnitConvertError {
@@ -168,20 +157,20 @@ impl fmt::Display for RadrootsCoreUnitConvertError {
#[cfg(feature = "std")]
impl std::error::Error for RadrootsCoreUnitConvertError {}
-impl FromStr for RadrootsCoreUnit {
+impl FromStr for Unit {
type Err = RadrootsCoreUnitParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.trim().to_ascii_lowercase();
match s.as_str() {
- "each" | "ea" | "count" => Ok(RadrootsCoreUnit::Each),
- "kg" | "kilogram" | "kilograms" => Ok(RadrootsCoreUnit::MassKg),
- "g" | "gram" | "grams" => Ok(RadrootsCoreUnit::MassG),
- "oz" | "ounce" | "ounces" => Ok(RadrootsCoreUnit::MassOz),
- "lb" | "pound" | "pounds" => Ok(RadrootsCoreUnit::MassLb),
- "l" | "liter" | "litre" | "liters" | "litres" => Ok(RadrootsCoreUnit::VolumeL),
+ "each" | "ea" | "count" => Ok(Unit::Each),
+ "kg" | "kilogram" | "kilograms" => Ok(Unit::MassKg),
+ "g" | "gram" | "grams" => Ok(Unit::MassG),
+ "oz" | "ounce" | "ounces" => Ok(Unit::MassOz),
+ "lb" | "pound" | "pounds" => Ok(Unit::MassLb),
+ "l" | "liter" | "litre" | "liters" | "litres" => Ok(Unit::VolumeL),
"ml" | "milliliter" | "millilitre" | "milliliters" | "millilitres" => {
- Ok(RadrootsCoreUnit::VolumeMl)
+ Ok(Unit::VolumeMl)
}
_ => Err(RadrootsCoreUnitParseError::UnknownUnit),
}
@@ -189,23 +178,29 @@ impl FromStr for RadrootsCoreUnit {
}
#[cfg(feature = "serde")]
-impl Serialize for RadrootsCoreUnit {
+impl Serialize for Unit {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(self.code())
}
}
#[cfg(feature = "serde")]
-impl<'de> Deserialize<'de> for RadrootsCoreUnit {
+impl<'de> Deserialize<'de> for Unit {
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
let s = String::deserialize(de)?;
s.parse().map_err(D::Error::custom)
}
}
+#[deprecated(since = "0.1.0", note = "renamed to `UnitDimension`")]
+pub use self::UnitDimension as RadrootsCoreUnitDimension;
+
+#[deprecated(since = "0.1.0", note = "renamed to `Unit`")]
+pub use self::Unit as RadrootsCoreUnit;
+
#[inline]
-pub fn parse_mass_unit(s: &str) -> Result<RadrootsCoreUnit, RadrootsCoreUnitParseError> {
- let u: RadrootsCoreUnit = RadrootsCoreUnit::from_str(s)?;
+pub fn parse_mass_unit(s: &str) -> Result<Unit, RadrootsCoreUnitParseError> {
+ let u: Unit = Unit::from_str(s)?;
if u.is_mass() {
Ok(u)
} else {
@@ -214,8 +209,8 @@ pub fn parse_mass_unit(s: &str) -> Result<RadrootsCoreUnit, RadrootsCoreUnitPars
}
#[inline]
-pub fn parse_volume_unit(s: &str) -> Result<RadrootsCoreUnit, RadrootsCoreUnitParseError> {
- let u: RadrootsCoreUnit = RadrootsCoreUnit::from_str(s)?;
+pub fn parse_volume_unit(s: &str) -> Result<Unit, RadrootsCoreUnitParseError> {
+ let u: Unit = Unit::from_str(s)?;
if u.is_volume() {
Ok(u)
} else {
@@ -225,25 +220,25 @@ pub fn parse_volume_unit(s: &str) -> Result<RadrootsCoreUnit, RadrootsCoreUnitPa
#[inline]
pub fn convert_mass_decimal(
- amount: RadrootsCoreDecimal,
- from: RadrootsCoreUnit,
- to: RadrootsCoreUnit,
-) -> Result<RadrootsCoreDecimal, RadrootsCoreUnitConvertError> {
+ amount: Decimal,
+ from: Unit,
+ to: Unit,
+) -> Result<Decimal, RadrootsCoreUnitConvertError> {
let amount_g = match from {
- RadrootsCoreUnit::MassG => amount,
- RadrootsCoreUnit::MassKg => amount * RadrootsCoreDecimal::from(1000u32),
- RadrootsCoreUnit::MassOz => amount * RadrootsCoreDecimal(dec!(28.349523125)),
- RadrootsCoreUnit::MassLb => amount * RadrootsCoreDecimal(dec!(453.59237)),
+ Unit::MassG => amount,
+ Unit::MassKg => amount * Decimal::from(1000u32),
+ Unit::MassOz => amount * Decimal(dec!(28.349523125)),
+ Unit::MassLb => amount * Decimal(dec!(453.59237)),
_ => {
return Err(RadrootsCoreUnitConvertError::NotMassUnit { from, to });
}
};
let to_factor = match to {
- RadrootsCoreUnit::MassG => RadrootsCoreDecimal::ONE,
- RadrootsCoreUnit::MassKg => RadrootsCoreDecimal::from(1000u32),
- RadrootsCoreUnit::MassOz => RadrootsCoreDecimal(dec!(28.349523125)),
- RadrootsCoreUnit::MassLb => RadrootsCoreDecimal(dec!(453.59237)),
+ Unit::MassG => Decimal::ONE,
+ Unit::MassKg => Decimal::from(1000u32),
+ Unit::MassOz => Decimal(dec!(28.349523125)),
+ Unit::MassLb => Decimal(dec!(453.59237)),
_ => {
return Err(RadrootsCoreUnitConvertError::NotMassUnit { from, to });
}
@@ -254,21 +249,21 @@ pub fn convert_mass_decimal(
#[inline]
pub fn convert_volume_decimal(
- amount: RadrootsCoreDecimal,
- from: RadrootsCoreUnit,
- to: RadrootsCoreUnit,
-) -> Result<RadrootsCoreDecimal, RadrootsCoreUnitConvertError> {
+ amount: Decimal,
+ from: Unit,
+ to: Unit,
+) -> Result<Decimal, RadrootsCoreUnitConvertError> {
let amount_ml = match from {
- RadrootsCoreUnit::VolumeMl => amount,
- RadrootsCoreUnit::VolumeL => amount * RadrootsCoreDecimal::from(1000u32),
+ Unit::VolumeMl => amount,
+ Unit::VolumeL => amount * Decimal::from(1000u32),
_ => {
return Err(RadrootsCoreUnitConvertError::NotVolumeUnit { from, to });
}
};
let to_factor = match to {
- RadrootsCoreUnit::VolumeMl => RadrootsCoreDecimal::ONE,
- RadrootsCoreUnit::VolumeL => RadrootsCoreDecimal::from(1000u32),
+ Unit::VolumeMl => Decimal::ONE,
+ Unit::VolumeL => Decimal::from(1000u32),
_ => {
return Err(RadrootsCoreUnitConvertError::NotVolumeUnit { from, to });
}
@@ -279,17 +274,17 @@ pub fn convert_volume_decimal(
#[inline]
pub fn convert_unit_decimal(
- amount: RadrootsCoreDecimal,
- from: RadrootsCoreUnit,
- to: RadrootsCoreUnit,
-) -> Result<RadrootsCoreDecimal, RadrootsCoreUnitConvertError> {
- if !RadrootsCoreUnit::same_dimension(from, to) {
+ amount: Decimal,
+ from: Unit,
+ to: Unit,
+) -> Result<Decimal, RadrootsCoreUnitConvertError> {
+ if !Unit::same_dimension(from, to) {
return Err(RadrootsCoreUnitConvertError::NotConvertibleUnits { from, to });
}
match from.dimension() {
- RadrootsCoreUnitDimension::Count => Ok(amount),
- RadrootsCoreUnitDimension::Mass => convert_mass_decimal(amount, from, to),
- RadrootsCoreUnitDimension::Volume => convert_volume_decimal(amount, from, to),
+ UnitDimension::Count => Ok(amount),
+ UnitDimension::Mass => convert_mass_decimal(amount, from, to),
+ UnitDimension::Volume => convert_volume_decimal(amount, from, to),
}
}
@@ -300,25 +295,17 @@ mod tests {
#[test]
fn convert_paths_cover_unit_branches() {
assert_eq!(
- convert_mass_decimal(
- RadrootsCoreDecimal::ONE,
- RadrootsCoreUnit::Each,
- RadrootsCoreUnit::MassG
- ),
+ convert_mass_decimal(Decimal::ONE, Unit::Each, Unit::MassG),
Err(RadrootsCoreUnitConvertError::NotMassUnit {
- from: RadrootsCoreUnit::Each,
- to: RadrootsCoreUnit::MassG
+ from: Unit::Each,
+ to: Unit::MassG
})
);
assert_eq!(
- convert_volume_decimal(
- RadrootsCoreDecimal::ONE,
- RadrootsCoreUnit::Each,
- RadrootsCoreUnit::VolumeMl
- ),
+ convert_volume_decimal(Decimal::ONE, Unit::Each, Unit::VolumeMl),
Err(RadrootsCoreUnitConvertError::NotVolumeUnit {
- from: RadrootsCoreUnit::Each,
- to: RadrootsCoreUnit::VolumeMl
+ from: Unit::Each,
+ to: Unit::VolumeMl
})
);
}
diff --git a/crates/core/tests/common/mod.rs b/crates/core/tests/common/mod.rs
@@ -2,27 +2,24 @@
use core::str::FromStr;
-use radroots_core::{
- RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCorePercent,
- RadrootsCoreQuantity, RadrootsCoreUnit,
-};
+use radroots_core::{Currency, Decimal, Money, Percent, Quantity, Unit};
-pub fn dec(s: &str) -> RadrootsCoreDecimal {
- RadrootsCoreDecimal::from_str(s).expect("valid decimal")
+pub fn dec(s: &str) -> Decimal {
+ Decimal::from_str(s).expect("valid decimal")
}
-pub fn currency(code: &str) -> RadrootsCoreCurrency {
- RadrootsCoreCurrency::from_str(code).expect("valid currency")
+pub fn currency(code: &str) -> Currency {
+ Currency::from_str(code).expect("valid currency")
}
-pub fn money(amount: &str, code: &str) -> RadrootsCoreMoney {
- RadrootsCoreMoney::new(dec(amount), currency(code))
+pub fn money(amount: &str, code: &str) -> Money {
+ Money::new(dec(amount), currency(code))
}
-pub fn qty(amount: &str, unit: RadrootsCoreUnit) -> RadrootsCoreQuantity {
- RadrootsCoreQuantity::new(dec(amount), unit)
+pub fn qty(amount: &str, unit: Unit) -> Quantity {
+ Quantity::new(dec(amount), unit)
}
-pub fn percent(s: &str) -> RadrootsCorePercent {
- RadrootsCorePercent::from_str(s).expect("valid percent")
+pub fn percent(s: &str) -> Percent {
+ Percent::from_str(s).expect("valid percent")
}
diff --git a/crates/core/tests/currency.rs b/crates/core/tests/currency.rs
@@ -1,69 +1,69 @@
use core::str::FromStr;
-use radroots_core::{RadrootsCoreCurrency, RadrootsCoreCurrencyParseError};
+use radroots_core::{Currency, RadrootsCoreCurrencyParseError};
#[test]
fn from_str_upper_accepts_valid() {
- let usd = RadrootsCoreCurrency::from_str_upper("USD").unwrap();
+ let usd = Currency::from_str_upper("USD").unwrap();
assert_eq!(usd.as_str(), "USD");
}
#[test]
fn from_str_upper_rejects_invalid() {
assert_eq!(
- RadrootsCoreCurrency::from_str_upper("Usd"),
+ Currency::from_str_upper("Usd"),
Err(RadrootsCoreCurrencyParseError::InvalidFormat)
);
assert_eq!(
- RadrootsCoreCurrency::from_str_upper("US"),
+ Currency::from_str_upper("US"),
Err(RadrootsCoreCurrencyParseError::InvalidFormat)
);
}
#[test]
fn from_str_trims_and_uppercases() {
- let usd = RadrootsCoreCurrency::from_str(" usd ").unwrap();
+ let usd = Currency::from_str(" usd ").unwrap();
assert_eq!(usd.as_str(), "USD");
}
#[test]
fn from_str_rejects_non_alpha() {
assert_eq!(
- RadrootsCoreCurrency::from_str("US1"),
+ Currency::from_str("US1"),
Err(RadrootsCoreCurrencyParseError::InvalidFormat)
);
assert_eq!(
- RadrootsCoreCurrency::from_str("US"),
+ Currency::from_str("US"),
Err(RadrootsCoreCurrencyParseError::InvalidFormat)
);
}
#[test]
fn from_const_validates_bytes() {
- assert!(RadrootsCoreCurrency::from_const(*b"USD").is_ok());
+ assert!(Currency::from_const(*b"USD").is_ok());
assert_eq!(
- RadrootsCoreCurrency::from_const(*b"1SD"),
+ Currency::from_const(*b"1SD"),
Err(RadrootsCoreCurrencyParseError::InvalidFormat)
);
assert_eq!(
- RadrootsCoreCurrency::from_const(*b"Usd"),
+ Currency::from_const(*b"Usd"),
Err(RadrootsCoreCurrencyParseError::InvalidFormat)
);
assert_eq!(
- RadrootsCoreCurrency::from_const(*b"USd"),
+ Currency::from_const(*b"USd"),
Err(RadrootsCoreCurrencyParseError::InvalidFormat)
);
assert_eq!(
- RadrootsCoreCurrency::from_const(*b"usd"),
+ Currency::from_const(*b"usd"),
Err(RadrootsCoreCurrencyParseError::InvalidFormat)
);
}
#[test]
fn minor_unit_exponent_matches_known_currencies() {
- let jpy = RadrootsCoreCurrency::from_str_upper("JPY").unwrap();
- let kwd = RadrootsCoreCurrency::from_str_upper("KWD").unwrap();
- let usd = RadrootsCoreCurrency::from_str_upper("USD").unwrap();
+ let jpy = Currency::from_str_upper("JPY").unwrap();
+ let kwd = Currency::from_str_upper("KWD").unwrap();
+ let usd = Currency::from_str_upper("USD").unwrap();
assert_eq!(jpy.minor_unit_exponent(), 0);
assert_eq!(kwd.minor_unit_exponent(), 3);
@@ -72,10 +72,10 @@ fn minor_unit_exponent_matches_known_currencies() {
#[test]
fn display_debug_tryfrom_and_error_display_paths_are_exercised() {
- let usd = RadrootsCoreCurrency::from_str("usd").unwrap();
+ let usd = Currency::from_str("usd").unwrap();
assert_eq!(usd.to_string(), "USD");
- assert_eq!(format!("{usd:?}"), "RadrootsCoreCurrency(\"USD\")");
- let via_try_from = RadrootsCoreCurrency::try_from("usd").unwrap();
+ assert_eq!(format!("{usd:?}"), "Currency(\"USD\")");
+ let via_try_from = Currency::try_from("usd").unwrap();
assert_eq!(via_try_from, usd);
assert_eq!(
RadrootsCoreCurrencyParseError::InvalidFormat.to_string(),
@@ -86,10 +86,10 @@ fn display_debug_tryfrom_and_error_display_paths_are_exercised() {
#[cfg(feature = "serde")]
#[test]
fn serde_deserialize_paths_are_exercised() {
- let parsed: RadrootsCoreCurrency = serde_json::from_str("\"USD\"").unwrap();
+ let parsed: Currency = serde_json::from_str("\"USD\"").unwrap();
assert_eq!(parsed.as_str(), "USD");
- let err = serde_json::from_str::<RadrootsCoreCurrency>("\"US1\"").unwrap_err();
+ let err = serde_json::from_str::<Currency>("\"US1\"").unwrap_err();
assert!(err.to_string().contains("currency must be a 3-letter code"));
- let non_string_err = serde_json::from_str::<RadrootsCoreCurrency>("123").unwrap_err();
+ let non_string_err = serde_json::from_str::<Currency>("123").unwrap_err();
assert!(non_string_err.to_string().contains("invalid type"));
}
diff --git a/crates/core/tests/decimal.rs b/crates/core/tests/decimal.rs
@@ -2,17 +2,17 @@ mod common;
use core::str::FromStr;
-use radroots_core::RadrootsCoreDecimal;
+use radroots_core::Decimal;
#[test]
fn display_normalizes_trailing_zeros() {
- let d = RadrootsCoreDecimal::from_str("1.2300").unwrap();
+ let d = Decimal::from_str("1.2300").unwrap();
assert_eq!(d.to_string(), "1.23");
}
#[test]
fn scale_reflects_input_precision() {
- let d = RadrootsCoreDecimal::from_str("1.2300").unwrap();
+ let d = Decimal::from_str("1.2300").unwrap();
assert_eq!(d.scale(), 4);
}
@@ -26,25 +26,25 @@ fn to_u64_exact_requires_whole_number() {
#[test]
fn from_f64_display_roundtrips_reasonably() {
- let d = RadrootsCoreDecimal::from_f64_display(1.25).unwrap();
+ let d = Decimal::from_f64_display(1.25).unwrap();
let v = d.to_f64_lossy().expect("f64 conversion");
assert!((v - 1.25).abs() < 1e-12);
}
#[test]
fn from_str_exact_and_conversion_impl_paths_are_exercised() {
- let exact = RadrootsCoreDecimal::from_str_exact("42.000").unwrap();
+ let exact = Decimal::from_str_exact("42.000").unwrap();
assert_eq!(exact, common::dec("42"));
- let from_decimal = RadrootsCoreDecimal::from(rust_decimal::Decimal::from(5u32));
+ let from_decimal = Decimal::from(rust_decimal::Decimal::from(5u32));
assert_eq!(from_decimal, common::dec("5"));
let back: rust_decimal::Decimal = from_decimal.into();
assert_eq!(back, rust_decimal::Decimal::from(5u32));
- let from_u32 = RadrootsCoreDecimal::from(7u32);
- let from_i32 = RadrootsCoreDecimal::from(-2i32);
- let from_u64 = RadrootsCoreDecimal::from(11u64);
- let from_i64 = RadrootsCoreDecimal::from(-9i64);
+ let from_u32 = Decimal::from(7u32);
+ let from_i32 = Decimal::from(-2i32);
+ let from_u64 = Decimal::from(11u64);
+ let from_i64 = Decimal::from(-9i64);
assert_eq!(from_u32, common::dec("7"));
assert_eq!(from_i32, common::dec("-2"));
assert_eq!(from_u64, common::dec("11"));
@@ -54,8 +54,8 @@ fn from_str_exact_and_conversion_impl_paths_are_exercised() {
#[cfg(feature = "serde")]
#[test]
fn serde_deserialize_error_paths_are_exercised() {
- let parse_err = serde_json::from_str::<RadrootsCoreDecimal>("\"not-a-decimal\"").unwrap_err();
+ let parse_err = serde_json::from_str::<Decimal>("\"not-a-decimal\"").unwrap_err();
assert!(!parse_err.to_string().is_empty());
- let non_string_err = serde_json::from_str::<RadrootsCoreDecimal>("123").unwrap_err();
+ let non_string_err = serde_json::from_str::<Decimal>("123").unwrap_err();
assert!(non_string_err.to_string().contains("invalid type"));
}
diff --git a/crates/core/tests/discount.rs b/crates/core/tests/discount.rs
@@ -1,18 +1,18 @@
mod common;
use radroots_core::{
- RadrootsCoreDiscount, RadrootsCoreDiscountScope, RadrootsCoreDiscountThreshold,
- RadrootsCoreDiscountValue, RadrootsCorePercent, RadrootsCoreUnit,
+ Percent, RadrootsCoreDiscount, RadrootsCoreDiscountScope, RadrootsCoreDiscountThreshold,
+ RadrootsCoreDiscountValue, Unit,
};
#[test]
fn is_non_negative_validates_discount_shapes() {
let money_pos = common::money("1", "USD");
let money_neg = common::money("-1", "USD");
- let qty_pos = common::qty("1", RadrootsCoreUnit::Each);
- let qty_neg = common::qty("-1", RadrootsCoreUnit::Each);
- let pct_pos = RadrootsCorePercent::new(common::dec("10"));
- let pct_neg = RadrootsCorePercent::new(common::dec("-5"));
+ let qty_pos = common::qty("1", Unit::Each);
+ let qty_neg = common::qty("-1", Unit::Each);
+ let pct_pos = Percent::new(common::dec("10"));
+ let pct_neg = Percent::new(common::dec("-5"));
let d = RadrootsCoreDiscount {
scope: RadrootsCoreDiscountScope::Bin,
diff --git a/crates/core/tests/money.rs b/crates/core/tests/money.rs
@@ -1,19 +1,19 @@
mod common;
-use radroots_core::{RadrootsCoreCurrency, RadrootsCoreMoney, RadrootsCoreMoneyInvariantError};
+use radroots_core::{Currency, Money, RadrootsCoreMoneyInvariantError};
use rust_decimal::RoundingStrategy;
#[test]
fn zero_and_is_zero() {
- let usd = RadrootsCoreCurrency::USD;
- let zero = RadrootsCoreMoney::zero(usd);
+ let usd = Currency::USD;
+ let zero = Money::zero(usd);
assert!(zero.is_zero());
assert_eq!(zero.currency, usd);
}
#[test]
fn ensure_non_negative_rejects_negative_amount() {
- let money = RadrootsCoreMoney::new(common::dec("-1"), RadrootsCoreCurrency::USD);
+ let money = Money::new(common::dec("-1"), Currency::USD);
assert_eq!(
money.ensure_non_negative(),
Err(RadrootsCoreMoneyInvariantError::NegativeAmount)
@@ -22,18 +22,18 @@ fn ensure_non_negative_rejects_negative_amount() {
#[test]
fn ensure_non_negative_accepts_zero_and_positive() {
- let zero = RadrootsCoreMoney::new(common::dec("0"), RadrootsCoreCurrency::USD);
- let pos = RadrootsCoreMoney::new(common::dec("1"), RadrootsCoreCurrency::USD);
+ let zero = Money::new(common::dec("0"), Currency::USD);
+ let pos = Money::new(common::dec("1"), Currency::USD);
assert_eq!(zero.ensure_non_negative(), Ok(()));
assert_eq!(pos.ensure_non_negative(), Ok(()));
}
#[test]
fn quantize_to_currency_rounds_midpoint_away_from_zero() {
- let usd = RadrootsCoreCurrency::USD;
- let a = RadrootsCoreMoney::new(common::dec("1.234"), usd).quantize_to_currency();
- let b = RadrootsCoreMoney::new(common::dec("1.235"), usd).quantize_to_currency();
- let c = RadrootsCoreMoney::new(common::dec("-1.235"), usd).quantize_to_currency();
+ let usd = Currency::USD;
+ let a = Money::new(common::dec("1.234"), usd).quantize_to_currency();
+ let b = Money::new(common::dec("1.235"), usd).quantize_to_currency();
+ let c = Money::new(common::dec("-1.235"), usd).quantize_to_currency();
assert_eq!(a.amount, common::dec("1.23"));
assert_eq!(b.amount, common::dec("1.24"));
@@ -42,10 +42,10 @@ fn quantize_to_currency_rounds_midpoint_away_from_zero() {
#[test]
fn quantize_to_currency_with_strategy_uses_strategy() {
- let usd = RadrootsCoreCurrency::USD;
- let a = RadrootsCoreMoney::new(common::dec("1.235"), usd)
+ let usd = Currency::USD;
+ let a = Money::new(common::dec("1.235"), usd)
.quantize_to_currency_with_strategy(RoundingStrategy::MidpointTowardZero);
- let b = RadrootsCoreMoney::new(common::dec("-1.235"), usd)
+ let b = Money::new(common::dec("-1.235"), usd)
.quantize_to_currency_with_strategy(RoundingStrategy::MidpointTowardZero);
assert_eq!(a.amount, common::dec("1.23"));
assert_eq!(b.amount, common::dec("-1.23"));
@@ -53,11 +53,11 @@ fn quantize_to_currency_with_strategy_uses_strategy() {
#[test]
fn checked_add_and_sub_require_currency_match() {
- let usd = RadrootsCoreCurrency::USD;
- let eur = RadrootsCoreCurrency::EUR;
- let a = RadrootsCoreMoney::new(common::dec("1.00"), usd);
- let b = RadrootsCoreMoney::new(common::dec("2.00"), usd);
- let c = RadrootsCoreMoney::new(common::dec("3.00"), eur);
+ let usd = Currency::USD;
+ let eur = Currency::EUR;
+ let a = Money::new(common::dec("1.00"), usd);
+ let b = Money::new(common::dec("2.00"), usd);
+ let c = Money::new(common::dec("3.00"), eur);
assert_eq!(a.checked_add(&b).unwrap().amount, common::dec("3.00"));
assert_eq!(
@@ -69,10 +69,10 @@ fn checked_add_and_sub_require_currency_match() {
#[test]
fn checked_sub_mismatch_returns_currency_error() {
- let usd = RadrootsCoreCurrency::USD;
- let eur = RadrootsCoreCurrency::EUR;
- let a = RadrootsCoreMoney::new(common::dec("1.00"), usd);
- let b = RadrootsCoreMoney::new(common::dec("2.00"), eur);
+ let usd = Currency::USD;
+ let eur = Currency::EUR;
+ let a = Money::new(common::dec("1.00"), usd);
+ let b = Money::new(common::dec("2.00"), eur);
assert_eq!(
a.checked_sub(&b),
Err(RadrootsCoreMoneyInvariantError::CurrencyMismatch)
@@ -81,10 +81,10 @@ fn checked_sub_mismatch_returns_currency_error() {
#[test]
fn minor_units_exact_and_rounded() {
- let usd = RadrootsCoreCurrency::USD;
- let exact = RadrootsCoreMoney::new(common::dec("1.23"), usd);
- let frac = RadrootsCoreMoney::new(common::dec("1.234"), usd);
- let rounded = RadrootsCoreMoney::new(common::dec("1.235"), usd);
+ let usd = Currency::USD;
+ let exact = Money::new(common::dec("1.23"), usd);
+ let frac = Money::new(common::dec("1.234"), usd);
+ let rounded = Money::new(common::dec("1.235"), usd);
assert_eq!(exact.to_minor_units_u64_exact().unwrap(), 123);
assert_eq!(
@@ -101,7 +101,7 @@ fn minor_units_exact_and_rounded() {
#[test]
fn minor_units_cover_additional_currency_exponents() {
- let jpy = RadrootsCoreMoney::new(common::dec("123"), common::currency("JPY"));
+ let jpy = Money::new(common::dec("123"), common::currency("JPY"));
assert_eq!(jpy.to_minor_units_u64_exact().unwrap(), 123);
assert_eq!(
jpy.to_minor_units_u64_rounded(RoundingStrategy::MidpointAwayFromZero)
@@ -109,14 +109,14 @@ fn minor_units_cover_additional_currency_exponents() {
123
);
- let kwd = RadrootsCoreMoney::new(common::dec("1.234"), common::currency("KWD"));
+ let kwd = Money::new(common::dec("1.234"), common::currency("KWD"));
assert_eq!(kwd.to_minor_units_u64_exact().unwrap(), 1234);
}
#[test]
fn minor_units_u32_overflow_is_detected() {
- let usd = RadrootsCoreCurrency::USD;
- let too_large = RadrootsCoreMoney::from_minor_units_u64(u64::from(u32::MAX) + 1, usd);
+ let usd = Currency::USD;
+ let too_large = Money::from_minor_units_u64(u64::from(u32::MAX) + 1, usd);
assert_eq!(
too_large.to_minor_units_u32_exact(),
Err(RadrootsCoreMoneyInvariantError::AmountOverflow)
@@ -125,10 +125,10 @@ fn minor_units_u32_overflow_is_detected() {
#[test]
fn minor_units_u32_exact_success_path_is_exercised() {
- let usd = RadrootsCoreCurrency::USD;
- let m = RadrootsCoreMoney::new(common::dec("42.01"), usd);
+ let usd = Currency::USD;
+ let m = Money::new(common::dec("42.01"), usd);
assert_eq!(m.to_minor_units_u32_exact().unwrap(), 4201);
- let fractional = RadrootsCoreMoney::new(common::dec("1.001"), usd);
+ let fractional = Money::new(common::dec("1.001"), usd);
assert_eq!(
fractional.to_minor_units_u32_exact(),
Err(RadrootsCoreMoneyInvariantError::NotWholeMinorUnits)
@@ -137,8 +137,8 @@ fn minor_units_u32_exact_success_path_is_exercised() {
#[test]
fn from_minor_units_u32_and_u32_rounded_paths_are_exercised() {
- let usd = RadrootsCoreCurrency::USD;
- let from_u32 = RadrootsCoreMoney::from_minor_units_u32(505, usd);
+ let usd = Currency::USD;
+ let from_u32 = Money::from_minor_units_u32(505, usd);
assert_eq!(from_u32.amount, common::dec("5.05"));
assert_eq!(
from_u32
@@ -150,13 +150,13 @@ fn from_minor_units_u32_and_u32_rounded_paths_are_exercised() {
#[test]
fn minor_units_u32_rounded_overflow_is_detected() {
- let usd = RadrootsCoreCurrency::USD;
- let too_large = RadrootsCoreMoney::from_minor_units_u64(u64::from(u32::MAX) + 1, usd);
+ let usd = Currency::USD;
+ let too_large = Money::from_minor_units_u64(u64::from(u32::MAX) + 1, usd);
assert_eq!(
too_large.to_minor_units_u32_rounded(RoundingStrategy::MidpointAwayFromZero),
Err(RadrootsCoreMoneyInvariantError::AmountOverflow)
);
- let negative = RadrootsCoreMoney::new(common::dec("-1.00"), usd);
+ let negative = Money::new(common::dec("-1.00"), usd);
assert_eq!(
negative.to_minor_units_u32_rounded(RoundingStrategy::MidpointAwayFromZero),
Err(RadrootsCoreMoneyInvariantError::AmountOverflow)
@@ -165,22 +165,22 @@ fn minor_units_u32_rounded_overflow_is_detected() {
#[test]
fn with_scale_path_is_exercised() {
- let usd = RadrootsCoreCurrency::USD;
- let m = RadrootsCoreMoney::new(common::dec("1.2300"), usd).with_scale(1);
+ let usd = Currency::USD;
+ let m = Money::new(common::dec("1.2300"), usd).with_scale(1);
assert_eq!(m.amount, common::dec("1.2"));
}
#[test]
fn from_minor_units_roundtrips() {
- let usd = RadrootsCoreCurrency::USD;
- let money = RadrootsCoreMoney::from_minor_units_u64(12345, usd);
+ let usd = Currency::USD;
+ let money = Money::from_minor_units_u64(12345, usd);
assert_eq!(money.to_minor_units_u64_exact().unwrap(), 12345);
}
#[test]
fn display_and_operator_impl_paths_are_exercised() {
- let usd = RadrootsCoreCurrency::USD;
- let m = RadrootsCoreMoney::new(common::dec("10"), usd);
+ let usd = Currency::USD;
+ let m = Money::new(common::dec("10"), usd);
assert_eq!(m.to_string(), "10 USD");
let times = m.clone() * common::dec("2");
diff --git a/crates/core/tests/package_boundary.rs b/crates/core/tests/package_boundary.rs
@@ -1,7 +1,39 @@
+use radroots_core::unit::UnitDimension;
#[allow(unused_imports)]
use radroots_core::{
- currency as _, decimal as _, money as _, percent as _, pricing as _, quantity as _, unit as _,
+ Currency, Decimal, Money, Percent, Quantity, QuantityPrice, Unit, currency as _, decimal as _,
+ money as _, percent as _, pricing as _, quantity as _, unit as _,
};
#[test]
fn approved_module_skeleton_is_public() {}
+
+#[test]
+fn canonical_value_paths_are_public() {
+ let _ = core::mem::size_of::<Currency>();
+ let _ = core::mem::size_of::<Decimal>();
+ let _ = core::mem::size_of::<Money>();
+ let _ = core::mem::size_of::<Percent>();
+ let _ = core::mem::size_of::<Quantity>();
+ let _ = core::mem::size_of::<QuantityPrice>();
+ let _ = core::mem::size_of::<Unit>();
+ let _ = UnitDimension::Count;
+}
+
+#[allow(deprecated)]
+#[test]
+fn temporary_legacy_aliases_remain_source_compatible() {
+ use radroots_core::{
+ RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCorePercent,
+ RadrootsCoreQuantity, RadrootsCoreQuantityPrice, RadrootsCoreUnit,
+ RadrootsCoreUnitDimension,
+ };
+
+ let decimal = RadrootsCoreDecimal(rust_decimal::Decimal::ONE);
+ let currency = RadrootsCoreCurrency::USD;
+ let money = RadrootsCoreMoney::new(decimal, currency);
+ let quantity = RadrootsCoreQuantity::new(decimal, RadrootsCoreUnit::Each);
+ let _ = RadrootsCorePercent::new(decimal);
+ let _ = RadrootsCoreQuantityPrice::new(money, quantity);
+ let _ = RadrootsCoreUnitDimension::Count;
+}
diff --git a/crates/core/tests/percent.rs b/crates/core/tests/percent.rs
@@ -2,25 +2,25 @@ mod common;
use core::str::FromStr;
-use radroots_core::{RadrootsCorePercent, RadrootsCorePercentParseError};
+use radroots_core::{Percent, RadrootsCorePercentParseError};
#[test]
fn ratio_roundtrip() {
- let pct = RadrootsCorePercent::from_ratio(common::dec("0.125"));
+ let pct = Percent::from_ratio(common::dec("0.125"));
assert_eq!(pct.value, common::dec("12.5"));
assert_eq!(pct.to_ratio(), common::dec("0.125"));
}
#[test]
fn parses_percent_strings() {
- let pct = RadrootsCorePercent::from_str("12.5%").unwrap();
+ let pct = Percent::from_str("12.5%").unwrap();
assert_eq!(pct.value, common::dec("12.5"));
- let pct = RadrootsCorePercent::from_str(" 12.5 ").unwrap();
+ let pct = Percent::from_str(" 12.5 ").unwrap();
assert_eq!(pct.value, common::dec("12.5"));
assert_eq!(
- RadrootsCorePercent::from_str("nope"),
+ Percent::from_str("nope"),
Err(RadrootsCorePercentParseError::InvalidNumber)
);
}
@@ -28,19 +28,19 @@ fn parses_percent_strings() {
#[test]
fn of_money_and_quantized() {
let base = common::money("20.00", "USD");
- let pct = RadrootsCorePercent::from_str("10").unwrap();
+ let pct = Percent::from_str("10").unwrap();
let out = pct.of_money(&base);
assert_eq!(out.amount, common::dec("2.00"));
let tiny = common::money("0.05", "USD");
- let pct = RadrootsCorePercent::from_str("10").unwrap();
+ let pct = Percent::from_str("10").unwrap();
let rounded = pct.of_money_quantized(&tiny);
assert_eq!(rounded.amount, common::dec("0.01"));
}
#[test]
fn display_and_parse_error_display_paths_are_exercised() {
- let pct = RadrootsCorePercent::from_str("12.5%").unwrap();
+ let pct = Percent::from_str("12.5%").unwrap();
assert_eq!(pct.to_string(), "12.5%");
assert_eq!(
RadrootsCorePercentParseError::InvalidNumber.to_string(),
diff --git a/crates/core/tests/quantity.rs b/crates/core/tests/quantity.rs
@@ -1,27 +1,27 @@
mod common;
-use radroots_core::{RadrootsCoreQuantityInvariantError, RadrootsCoreUnit};
+use radroots_core::{RadrootsCoreQuantityInvariantError, Unit};
#[test]
fn zero_helpers_and_scale_paths_are_exercised() {
- let zero = radroots_core::RadrootsCoreQuantity::zero(RadrootsCoreUnit::MassKg);
+ let zero = radroots_core::Quantity::zero(Unit::MassKg);
assert!(zero.is_zero());
- assert_eq!(zero.canonical_unit(), RadrootsCoreUnit::MassG);
+ assert_eq!(zero.canonical_unit(), Unit::MassG);
assert!(!zero.is_canonical());
- let scaled = common::qty("1.2300", RadrootsCoreUnit::Each).with_scale(1);
+ let scaled = common::qty("1.2300", Unit::Each).with_scale(1);
assert_eq!(scaled.amount, common::dec("1.2"));
}
#[test]
fn label_helpers_set_and_clear() {
- let q = common::qty("1", RadrootsCoreUnit::Each).with_label("box");
+ let q = common::qty("1", Unit::Each).with_label("box");
assert_eq!(q.label.as_deref(), Some("box"));
let q = q.clear_label();
assert!(q.label.is_none());
- let q = common::qty("1", RadrootsCoreUnit::Each).with_optional_label(Some("case"));
+ let q = common::qty("1", Unit::Each).with_optional_label(Some("case"));
assert_eq!(q.label.as_deref(), Some("case"));
let q = q.with_optional_label::<&str>(None);
@@ -30,7 +30,7 @@ fn label_helpers_set_and_clear() {
#[test]
fn ensure_non_negative_rejects_negative_amount() {
- let q = common::qty("-1", RadrootsCoreUnit::Each);
+ let q = common::qty("-1", Unit::Each);
assert_eq!(
q.ensure_non_negative(),
Err(RadrootsCoreQuantityInvariantError::NegativeAmount)
@@ -39,15 +39,15 @@ fn ensure_non_negative_rejects_negative_amount() {
#[test]
fn ensure_non_negative_accepts_non_negative_amount() {
- let q = common::qty("0", RadrootsCoreUnit::Each);
+ let q = common::qty("0", Unit::Each);
assert_eq!(q.ensure_non_negative(), Ok(()));
}
#[test]
fn try_add_and_try_sub_require_matching_units() {
- let a = common::qty("1", RadrootsCoreUnit::Each).with_label("lhs");
- let b = common::qty("2", RadrootsCoreUnit::Each);
- let c = common::qty("1", RadrootsCoreUnit::MassKg);
+ let a = common::qty("1", Unit::Each).with_label("lhs");
+ let b = common::qty("2", Unit::Each);
+ let c = common::qty("1", Unit::MassKg);
let sum = a.try_add(&b).unwrap();
assert_eq!(sum.amount, common::dec("3"));
@@ -65,8 +65,8 @@ fn try_add_and_try_sub_require_matching_units() {
#[test]
fn try_sub_success_path_is_exercised() {
- let a = common::qty("4", RadrootsCoreUnit::Each).with_label("lhs");
- let b = common::qty("1", RadrootsCoreUnit::Each);
+ let a = common::qty("4", Unit::Each).with_label("lhs");
+ let b = common::qty("1", Unit::Each);
let out = a.try_sub(&b).expect("sub result");
assert_eq!(out.amount, common::dec("3"));
assert_eq!(out.label.as_deref(), Some("lhs"));
@@ -74,16 +74,16 @@ fn try_sub_success_path_is_exercised() {
#[test]
fn checked_add_and_sub_return_none_on_mismatch() {
- let a = common::qty("1", RadrootsCoreUnit::Each);
- let b = common::qty("2", RadrootsCoreUnit::MassG);
+ let a = common::qty("1", Unit::Each);
+ let b = common::qty("2", Unit::MassG);
assert!(a.checked_add(&b).is_none());
assert!(a.checked_sub(&b).is_none());
}
#[test]
fn checked_add_and_sub_return_some_on_matching_units() {
- let a = common::qty("5", RadrootsCoreUnit::Each).with_label("lhs");
- let b = common::qty("2", RadrootsCoreUnit::Each);
+ let a = common::qty("5", Unit::Each).with_label("lhs");
+ let b = common::qty("2", Unit::Each);
let added = a.checked_add(&b).expect("added quantity");
assert_eq!(added.amount, common::dec("7"));
assert_eq!(added.label.as_deref(), Some("lhs"));
@@ -95,21 +95,21 @@ fn checked_add_and_sub_return_some_on_matching_units() {
#[test]
fn mul_and_div_preserve_unit_and_label() {
- let q = common::qty("2", RadrootsCoreUnit::Each).with_label("unit");
+ let q = common::qty("2", Unit::Each).with_label("unit");
let scaled = q.clone().mul_decimal(common::dec("2.5"));
assert_eq!(scaled.amount, common::dec("5"));
- assert_eq!(scaled.unit, RadrootsCoreUnit::Each);
+ assert_eq!(scaled.unit, Unit::Each);
assert_eq!(scaled.label.as_deref(), Some("unit"));
let divided = q.div_decimal(common::dec("2"));
assert_eq!(divided.amount, common::dec("1"));
- assert_eq!(divided.unit, RadrootsCoreUnit::Each);
+ assert_eq!(divided.unit, Unit::Each);
assert_eq!(divided.label.as_deref(), Some("unit"));
}
#[test]
fn mul_and_div_operator_impls_are_exercised() {
- let qty = common::qty("4", RadrootsCoreUnit::Each).with_label("bag");
+ let qty = common::qty("4", Unit::Each).with_label("bag");
let mul = qty.clone() * common::dec("1.5");
assert_eq!(mul.amount, common::dec("6"));
assert_eq!(mul.label.as_deref(), Some("bag"));
@@ -121,13 +121,13 @@ fn mul_and_div_operator_impls_are_exercised() {
#[test]
fn display_includes_label_when_present() {
- let q = common::qty("1.5", RadrootsCoreUnit::Each).with_label("bag");
+ let q = common::qty("1.5", Unit::Each).with_label("bag");
assert_eq!(q.to_string(), "1.5 each (bag)");
}
#[test]
fn display_without_label_and_error_display_are_exercised() {
- let q = common::qty("1.5", RadrootsCoreUnit::Each);
+ let q = common::qty("1.5", Unit::Each);
assert_eq!(q.to_string(), "1.5 each");
assert_eq!(
@@ -164,7 +164,7 @@ fn display_propagates_formatter_errors() {
}
}
- let with_label = common::qty("1.5", RadrootsCoreUnit::Each).with_label("bag");
+ let with_label = common::qty("1.5", Unit::Each).with_label("bag");
let mut first_write_fails = FailWriter {
fail_on_paren: false,
fail_on_call: 1,
@@ -182,38 +182,36 @@ fn display_propagates_formatter_errors() {
#[test]
fn try_convert_to_changes_unit_and_amount() {
- let q = common::qty("1", RadrootsCoreUnit::MassKg);
- let converted = q.try_convert_to(RadrootsCoreUnit::MassG).unwrap();
+ let q = common::qty("1", Unit::MassKg);
+ let converted = q.try_convert_to(Unit::MassG).unwrap();
assert_eq!(converted.amount, common::dec("1000"));
- assert_eq!(converted.unit, RadrootsCoreUnit::MassG);
+ assert_eq!(converted.unit, Unit::MassG);
}
#[test]
fn to_canonical_converts_mass_and_volume() {
- let q = common::qty("2", RadrootsCoreUnit::VolumeL);
+ let q = common::qty("2", Unit::VolumeL);
let canonical = q.to_canonical().unwrap();
- assert_eq!(canonical.unit, RadrootsCoreUnit::VolumeMl);
+ assert_eq!(canonical.unit, Unit::VolumeMl);
assert_eq!(canonical.amount, common::dec("2000"));
}
#[test]
fn try_convert_to_rejects_mismatched_dimensions() {
- let q = common::qty("1", RadrootsCoreUnit::Each);
- let err = q.try_convert_to(RadrootsCoreUnit::MassG).unwrap_err();
+ let q = common::qty("1", Unit::Each);
+ let err = q.try_convert_to(Unit::MassG).unwrap_err();
assert_eq!(
err,
radroots_core::RadrootsCoreUnitConvertError::NotConvertibleUnits {
- from: RadrootsCoreUnit::Each,
- to: RadrootsCoreUnit::MassG
+ from: Unit::Each,
+ to: Unit::MassG
}
);
}
#[test]
fn try_convert_to_same_unit_returns_self_clone() {
- let q = common::qty("2", RadrootsCoreUnit::MassG).with_label("x");
- let converted = q
- .try_convert_to(RadrootsCoreUnit::MassG)
- .expect("same unit");
+ let q = common::qty("2", Unit::MassG).with_label("x");
+ let converted = q.try_convert_to(Unit::MassG).expect("same unit");
assert_eq!(converted, q);
}
diff --git a/crates/core/tests/quantity_price.rs b/crates/core/tests/quantity_price.rs
@@ -1,37 +1,27 @@
mod common;
use radroots_core::{
- RadrootsCoreQuantityPrice, RadrootsCoreQuantityPriceError, RadrootsCoreQuantityPriceOps,
- RadrootsCoreUnit,
+ QuantityPrice, RadrootsCoreQuantityPriceError, RadrootsCoreQuantityPriceOps, Unit,
};
#[test]
fn cost_for_scales_by_ratio() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("10", "USD"),
- common::qty("1", RadrootsCoreUnit::MassKg),
- );
- let cost = price.cost_for(&common::qty("2", RadrootsCoreUnit::MassKg));
+ let price = QuantityPrice::new(common::money("10", "USD"), common::qty("1", Unit::MassKg));
+ let cost = price.cost_for(&common::qty("2", Unit::MassKg));
assert_eq!(cost.amount, common::dec("20"));
}
#[test]
fn cost_for_returns_zero_on_unit_mismatch() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("10", "USD"),
- common::qty("1", RadrootsCoreUnit::MassKg),
- );
- let cost = price.cost_for(&common::qty("1", RadrootsCoreUnit::Each));
+ let price = QuantityPrice::new(common::money("10", "USD"), common::qty("1", Unit::MassKg));
+ let cost = price.cost_for(&common::qty("1", Unit::Each));
assert!(cost.amount.is_zero());
}
#[test]
fn cost_for_rounded_and_quantized_price_differ() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("1.005", "USD"),
- common::qty("1", RadrootsCoreUnit::Each),
- );
- let qty = common::qty("2", RadrootsCoreUnit::Each);
+ let price = QuantityPrice::new(common::money("1.005", "USD"), common::qty("1", Unit::Each));
+ let qty = common::qty("2", Unit::Each);
let rounded = price.cost_for_rounded(&qty);
let quantized = price.cost_for_with_quantized_price(&qty);
@@ -41,165 +31,127 @@ fn cost_for_rounded_and_quantized_price_differ() {
#[test]
fn try_cost_for_validates_quantity_and_units() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("10", "USD"),
- common::qty("1", RadrootsCoreUnit::Each),
- );
- let zero_price = RadrootsCoreQuantityPrice::new(
- common::money("10", "USD"),
- common::qty("0", RadrootsCoreUnit::Each),
- );
+ let price = QuantityPrice::new(common::money("10", "USD"), common::qty("1", Unit::Each));
+ let zero_price = QuantityPrice::new(common::money("10", "USD"), common::qty("0", Unit::Each));
assert_eq!(
- zero_price.try_cost_for(&common::qty("1", RadrootsCoreUnit::Each)),
+ zero_price.try_cost_for(&common::qty("1", Unit::Each)),
Err(RadrootsCoreQuantityPriceError::PerQuantityZero)
);
assert_eq!(
- price.try_cost_for(&common::qty("1", RadrootsCoreUnit::MassKg)),
+ price.try_cost_for(&common::qty("1", Unit::MassKg)),
Err(RadrootsCoreQuantityPriceError::UnitMismatch {
- have: RadrootsCoreUnit::MassKg,
- want: RadrootsCoreUnit::Each
+ have: Unit::MassKg,
+ want: Unit::Each
})
);
}
#[test]
fn try_cost_for_rounded_error_path_is_exercised() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("10", "USD"),
- common::qty("1", RadrootsCoreUnit::Each),
- );
+ let price = QuantityPrice::new(common::money("10", "USD"), common::qty("1", Unit::Each));
assert_eq!(
- price.try_cost_for_rounded(&common::qty("1", RadrootsCoreUnit::MassKg)),
+ price.try_cost_for_rounded(&common::qty("1", Unit::MassKg)),
Err(RadrootsCoreQuantityPriceError::UnitMismatch {
- have: RadrootsCoreUnit::MassKg,
- want: RadrootsCoreUnit::Each
+ have: Unit::MassKg,
+ want: Unit::Each
})
);
}
#[test]
fn try_cost_for_amount_in_converts_mass_units() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("10", "USD"),
- common::qty("1", RadrootsCoreUnit::MassKg),
- );
+ let price = QuantityPrice::new(common::money("10", "USD"), common::qty("1", Unit::MassKg));
let cost = price
- .try_cost_for_amount_in(common::dec("500"), RadrootsCoreUnit::MassG)
+ .try_cost_for_amount_in(common::dec("500"), Unit::MassG)
.unwrap();
assert_eq!(cost.amount, common::dec("5"));
}
#[test]
fn try_cost_for_amount_in_converts_volume_units() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("10", "USD"),
- common::qty("1", RadrootsCoreUnit::VolumeL),
- );
+ let price = QuantityPrice::new(common::money("10", "USD"), common::qty("1", Unit::VolumeL));
let cost = price
- .try_cost_for_amount_in(common::dec("500"), RadrootsCoreUnit::VolumeMl)
+ .try_cost_for_amount_in(common::dec("500"), Unit::VolumeMl)
.unwrap();
assert_eq!(cost.amount, common::dec("5"));
}
#[test]
fn try_cost_for_amount_in_rejects_non_convertible_units() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("10", "USD"),
- common::qty("1", RadrootsCoreUnit::MassKg),
- );
+ let price = QuantityPrice::new(common::money("10", "USD"), common::qty("1", Unit::MassKg));
assert_eq!(
- price.try_cost_for_amount_in(common::dec("1"), RadrootsCoreUnit::Each),
+ price.try_cost_for_amount_in(common::dec("1"), Unit::Each),
Err(RadrootsCoreQuantityPriceError::NonConvertibleUnits {
- from: RadrootsCoreUnit::Each,
- to: RadrootsCoreUnit::MassKg
+ from: Unit::Each,
+ to: Unit::MassKg
})
);
}
#[test]
fn try_cost_for_amount_in_same_unit_path_is_exercised() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("4", "USD"),
- common::qty("1", RadrootsCoreUnit::Each),
- );
+ let price = QuantityPrice::new(common::money("4", "USD"), common::qty("1", Unit::Each));
let out = price
- .try_cost_for_amount_in(common::dec("3"), RadrootsCoreUnit::Each)
+ .try_cost_for_amount_in(common::dec("3"), Unit::Each)
.unwrap();
assert_eq!(out.amount, common::dec("12"));
}
#[test]
fn try_cost_for_quantity_in_path_is_exercised() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("10", "USD"),
- common::qty("1", RadrootsCoreUnit::MassKg),
- );
- let qty = common::qty("250", RadrootsCoreUnit::MassG);
+ let price = QuantityPrice::new(common::money("10", "USD"), common::qty("1", Unit::MassKg));
+ let qty = common::qty("250", Unit::MassG);
let out = price.try_cost_for_quantity_in(&qty).unwrap();
assert_eq!(out.amount, common::dec("2.5"));
}
#[test]
fn try_to_unit_price_error_and_same_unit_paths_are_exercised() {
- let zero = RadrootsCoreQuantityPrice::new(
- common::money("10", "USD"),
- common::qty("0", RadrootsCoreUnit::MassKg),
- );
+ let zero = QuantityPrice::new(common::money("10", "USD"), common::qty("0", Unit::MassKg));
assert_eq!(
- zero.try_to_unit_price(RadrootsCoreUnit::MassG),
+ zero.try_to_unit_price(Unit::MassG),
Err(RadrootsCoreQuantityPriceError::PerQuantityZero)
);
- let base = RadrootsCoreQuantityPrice::new(
- common::money("5", "USD"),
- common::qty("2", RadrootsCoreUnit::MassKg),
- );
- let same = base.try_to_unit_price(RadrootsCoreUnit::MassKg).unwrap();
- assert_eq!(same.quantity.unit, RadrootsCoreUnit::MassKg);
+ let base = QuantityPrice::new(common::money("5", "USD"), common::qty("2", Unit::MassKg));
+ let same = base.try_to_unit_price(Unit::MassKg).unwrap();
+ assert_eq!(same.quantity.unit, Unit::MassKg);
assert_eq!(same.quantity.amount, common::dec("1"));
assert_eq!(same.amount.amount, common::dec("2.5"));
- let err = base
- .try_to_unit_price(RadrootsCoreUnit::VolumeMl)
- .unwrap_err();
+ let err = base.try_to_unit_price(Unit::VolumeMl).unwrap_err();
assert_eq!(
err,
RadrootsCoreQuantityPriceError::NonConvertibleUnits {
- from: RadrootsCoreUnit::MassKg,
- to: RadrootsCoreUnit::VolumeMl
+ from: Unit::MassKg,
+ to: Unit::VolumeMl
}
);
}
#[test]
fn cost_for_and_quantized_price_zero_paths_are_exercised() {
- let p = RadrootsCoreQuantityPrice::new(
- common::money("3.33", "USD"),
- common::qty("1", RadrootsCoreUnit::Each),
- );
- let zero_qty = common::qty("0", RadrootsCoreUnit::Each);
+ let p = QuantityPrice::new(common::money("3.33", "USD"), common::qty("1", Unit::Each));
+ let zero_qty = common::qty("0", Unit::Each);
assert!(p.cost_for(&zero_qty).amount.is_zero());
assert!(p.cost_for_with_quantized_price(&zero_qty).amount.is_zero());
- let zero_per = RadrootsCoreQuantityPrice::new(
- common::money("3.33", "USD"),
- common::qty("0", RadrootsCoreUnit::Each),
- );
+ let zero_per = QuantityPrice::new(common::money("3.33", "USD"), common::qty("0", Unit::Each));
assert!(
zero_per
- .cost_for(&common::qty("1", RadrootsCoreUnit::Each))
+ .cost_for(&common::qty("1", Unit::Each))
.amount
.is_zero()
);
assert!(
zero_per
- .cost_for_with_quantized_price(&common::qty("1", RadrootsCoreUnit::Each))
+ .cost_for_with_quantized_price(&common::qty("1", Unit::Each))
.amount
.is_zero()
);
- let mismatch_qty = common::qty("1", RadrootsCoreUnit::MassG);
+ let mismatch_qty = common::qty("1", Unit::MassG);
assert!(
p.cost_for_with_quantized_price(&mismatch_qty)
.amount
@@ -209,24 +161,19 @@ fn cost_for_and_quantized_price_zero_paths_are_exercised() {
#[test]
fn try_to_unit_price_detects_underflow_to_zero_normalized_amount() {
- let tiny = RadrootsCoreQuantityPrice::new(
+ let tiny = QuantityPrice::new(
common::money("1", "USD"),
- common::qty("0.0000000000000000000000000001", RadrootsCoreUnit::VolumeMl),
+ common::qty("0.0000000000000000000000000001", Unit::VolumeMl),
);
- let err = tiny
- .try_to_unit_price(RadrootsCoreUnit::VolumeL)
- .unwrap_err();
+ let err = tiny.try_to_unit_price(Unit::VolumeL).unwrap_err();
assert_eq!(err, RadrootsCoreQuantityPriceError::PerQuantityZero);
}
#[test]
fn try_to_canonical_unit_price_converts_units() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("6.99", "USD"),
- common::qty("1", RadrootsCoreUnit::MassLb),
- );
+ let price = QuantityPrice::new(common::money("6.99", "USD"), common::qty("1", Unit::MassLb));
let canonical = price.try_to_canonical_unit_price().unwrap();
- assert_eq!(canonical.quantity.unit, RadrootsCoreUnit::MassG);
+ assert_eq!(canonical.quantity.unit, Unit::MassG);
assert_eq!(canonical.quantity.amount, common::dec("1"));
let expected = common::dec("6.99") / common::dec("453.59237");
assert_eq!(canonical.amount.amount, expected);
@@ -234,15 +181,9 @@ fn try_to_canonical_unit_price_converts_units() {
#[test]
fn is_price_per_canonical_unit_detects_canonical() {
- let price = RadrootsCoreQuantityPrice::new(
- common::money("1.00", "USD"),
- common::qty("1", RadrootsCoreUnit::MassG),
- );
+ let price = QuantityPrice::new(common::money("1.00", "USD"), common::qty("1", Unit::MassG));
assert!(price.is_price_per_canonical_unit());
- let price = RadrootsCoreQuantityPrice::new(
- common::money("1.00", "USD"),
- common::qty("1", RadrootsCoreUnit::MassKg),
- );
+ let price = QuantityPrice::new(common::money("1.00", "USD"), common::qty("1", Unit::MassKg));
assert!(!price.is_price_per_canonical_unit());
}
diff --git a/crates/core/tests/serde.rs b/crates/core/tests/serde.rs
@@ -4,10 +4,7 @@ mod common;
use core::str::FromStr;
-use radroots_core::{
- RadrootsCoreCurrency, RadrootsCoreDecimal, RadrootsCoreMoney, RadrootsCorePercent,
- RadrootsCoreQuantity, RadrootsCoreUnit,
-};
+use radroots_core::{Currency, Decimal, Money, Percent, Quantity, Unit};
use serde_json::Value;
#[test]
@@ -16,13 +13,13 @@ fn decimal_serializes_as_string() {
let json = serde_json::to_string(&d).unwrap();
assert_eq!(json, "\"1.23\"");
- let back: RadrootsCoreDecimal = serde_json::from_str(&json).unwrap();
+ let back: Decimal = serde_json::from_str(&json).unwrap();
assert_eq!(back, common::dec("1.23"));
}
#[test]
fn quantity_uses_decimal_str_and_omits_empty_label() {
- let q = RadrootsCoreQuantity::new(common::dec("1.2300"), RadrootsCoreUnit::MassKg);
+ let q = Quantity::new(common::dec("1.2300"), Unit::MassKg);
let value = serde_json::to_value(&q).unwrap();
assert_eq!(value["amount"], Value::String("1.23".to_string()));
@@ -33,34 +30,34 @@ fn quantity_uses_decimal_str_and_omits_empty_label() {
#[test]
fn quantity_deserializes_decimal_str_via_serde_ext() {
let raw = r#"{"amount":"1.2300","unit":"kg","label":"bag"}"#;
- let q: RadrootsCoreQuantity = serde_json::from_str(raw).unwrap();
+ let q: Quantity = serde_json::from_str(raw).unwrap();
assert_eq!(q.amount, common::dec("1.23"));
- assert_eq!(q.unit, RadrootsCoreUnit::MassKg);
+ assert_eq!(q.unit, Unit::MassKg);
assert_eq!(q.label.as_deref(), Some("bag"));
}
#[test]
fn quantity_rejects_non_string_decimal_amount() {
let raw = r#"{"amount":1.23,"unit":"kg"}"#;
- let err = serde_json::from_str::<RadrootsCoreQuantity>(raw).unwrap_err();
+ let err = serde_json::from_str::<Quantity>(raw).unwrap_err();
assert!(err.to_string().contains("invalid type"));
}
#[test]
fn money_and_percent_roundtrip_with_strings() {
- let money = RadrootsCoreMoney::new(common::dec("2.50"), RadrootsCoreCurrency::USD);
+ let money = Money::new(common::dec("2.50"), Currency::USD);
let value = serde_json::to_value(&money).unwrap();
assert_eq!(value["amount"], Value::String("2.5".to_string()));
assert_eq!(value["currency"], Value::String("USD".to_string()));
- let pct = RadrootsCorePercent::new(common::dec("12.5"));
+ let pct = Percent::new(common::dec("12.5"));
let value = serde_json::to_value(&pct).unwrap();
assert_eq!(value["value"], Value::String("12.5".to_string()));
}
#[test]
fn currency_serializes_as_code() {
- let c = RadrootsCoreCurrency::from_str("usd").unwrap();
+ let c = Currency::from_str("usd").unwrap();
let json = serde_json::to_string(&c).unwrap();
assert_eq!(json, "\"USD\"");
}
diff --git a/crates/core/tests/unit.rs b/crates/core/tests/unit.rs
@@ -3,14 +3,13 @@ mod common;
use core::str::FromStr;
use radroots_core::{
- RadrootsCoreUnit, RadrootsCoreUnitConvertError, RadrootsCoreUnitParseError,
- convert_mass_decimal, convert_unit_decimal, convert_volume_decimal, parse_mass_unit,
- parse_volume_unit,
+ RadrootsCoreUnitConvertError, RadrootsCoreUnitParseError, Unit, convert_mass_decimal,
+ convert_unit_decimal, convert_volume_decimal, parse_mass_unit, parse_volume_unit,
};
#[test]
fn parses_units_and_synonyms() {
- use RadrootsCoreUnit::*;
+ use Unit::*;
let cases = [
("each", Each),
("ea", Each),
@@ -29,31 +28,31 @@ fn parses_units_and_synonyms() {
("milliliters", VolumeMl),
];
for (input, expected) in cases {
- assert_eq!(RadrootsCoreUnit::from_str(input).unwrap(), expected);
+ assert_eq!(Unit::from_str(input).unwrap(), expected);
}
}
#[test]
fn rejects_unknown_units() {
assert_eq!(
- RadrootsCoreUnit::from_str("unknown"),
+ Unit::from_str("unknown"),
Err(RadrootsCoreUnitParseError::UnknownUnit)
);
}
#[test]
fn same_dimension_matches_mass_and_volume_groups() {
- use RadrootsCoreUnit::*;
- assert!(RadrootsCoreUnit::same_dimension(MassKg, MassG));
- assert!(RadrootsCoreUnit::same_dimension(VolumeL, VolumeMl));
- assert!(RadrootsCoreUnit::same_dimension(Each, Each));
- assert!(!RadrootsCoreUnit::same_dimension(MassKg, VolumeL));
- assert!(!RadrootsCoreUnit::same_dimension(Each, MassG));
+ use Unit::*;
+ assert!(Unit::same_dimension(MassKg, MassG));
+ assert!(Unit::same_dimension(VolumeL, VolumeMl));
+ assert!(Unit::same_dimension(Each, Each));
+ assert!(!Unit::same_dimension(MassKg, VolumeL));
+ assert!(!Unit::same_dimension(Each, MassG));
}
#[test]
fn canonical_unit_maps_dimensions() {
- use RadrootsCoreUnit::*;
+ use Unit::*;
assert_eq!(Each.canonical_unit(), Each);
assert_eq!(MassKg.canonical_unit(), MassG);
assert_eq!(MassLb.canonical_unit(), MassG);
@@ -62,7 +61,7 @@ fn canonical_unit_maps_dimensions() {
#[test]
fn code_and_predicate_helpers_cover_all_variants() {
- use RadrootsCoreUnit::*;
+ use Unit::*;
assert_eq!(Each.code(), "each");
assert_eq!(MassKg.code(), "kg");
assert_eq!(MassG.code(), "g");
@@ -81,7 +80,7 @@ fn code_and_predicate_helpers_cover_all_variants() {
#[test]
fn parse_mass_unit_enforces_mass_only() {
- assert_eq!(parse_mass_unit("kg"), Ok(RadrootsCoreUnit::MassKg));
+ assert_eq!(parse_mass_unit("kg"), Ok(Unit::MassKg));
assert_eq!(
parse_mass_unit("each"),
Err(RadrootsCoreUnitParseError::NotAMassUnit)
@@ -94,7 +93,7 @@ fn parse_mass_unit_enforces_mass_only() {
#[test]
fn parse_volume_unit_enforces_volume_only() {
- assert_eq!(parse_volume_unit("l"), Ok(RadrootsCoreUnit::VolumeL));
+ assert_eq!(parse_volume_unit("l"), Ok(Unit::VolumeL));
assert_eq!(
parse_volume_unit("kg"),
Err(RadrootsCoreUnitParseError::NotAVolumeUnit)
@@ -107,7 +106,7 @@ fn parse_volume_unit_enforces_volume_only() {
#[test]
fn convert_mass_decimal_converts_between_mass_units() {
- use RadrootsCoreUnit::*;
+ use Unit::*;
let kg_to_g = convert_mass_decimal(common::dec("1"), MassKg, MassG).unwrap();
let g_to_kg = convert_mass_decimal(common::dec("1000"), MassG, MassKg).unwrap();
let lb_to_g = convert_mass_decimal(common::dec("1"), MassLb, MassG).unwrap();
@@ -125,38 +124,28 @@ fn convert_mass_decimal_converts_between_mass_units() {
#[test]
fn convert_mass_decimal_rejects_non_mass_units() {
- let err = convert_mass_decimal(
- common::dec("1"),
- RadrootsCoreUnit::Each,
- RadrootsCoreUnit::MassG,
- )
- .unwrap_err();
+ let err = convert_mass_decimal(common::dec("1"), Unit::Each, Unit::MassG).unwrap_err();
assert_eq!(
err,
RadrootsCoreUnitConvertError::NotMassUnit {
- from: RadrootsCoreUnit::Each,
- to: RadrootsCoreUnit::MassG
+ from: Unit::Each,
+ to: Unit::MassG
}
);
- let err = convert_mass_decimal(
- common::dec("1"),
- RadrootsCoreUnit::MassKg,
- RadrootsCoreUnit::Each,
- )
- .unwrap_err();
+ let err = convert_mass_decimal(common::dec("1"), Unit::MassKg, Unit::Each).unwrap_err();
assert_eq!(
err,
RadrootsCoreUnitConvertError::NotMassUnit {
- from: RadrootsCoreUnit::MassKg,
- to: RadrootsCoreUnit::Each
+ from: Unit::MassKg,
+ to: Unit::Each
}
);
}
#[test]
fn convert_volume_decimal_converts_between_volume_units() {
- use RadrootsCoreUnit::*;
+ use Unit::*;
let l_to_ml = convert_volume_decimal(common::dec("1"), VolumeL, VolumeMl).unwrap();
let ml_to_l = convert_volume_decimal(common::dec("250"), VolumeMl, VolumeL).unwrap();
assert_eq!(l_to_ml, common::dec("1000"));
@@ -165,38 +154,28 @@ fn convert_volume_decimal_converts_between_volume_units() {
#[test]
fn convert_volume_decimal_rejects_non_volume_units() {
- let err = convert_volume_decimal(
- common::dec("1"),
- RadrootsCoreUnit::Each,
- RadrootsCoreUnit::VolumeMl,
- )
- .unwrap_err();
+ let err = convert_volume_decimal(common::dec("1"), Unit::Each, Unit::VolumeMl).unwrap_err();
assert_eq!(
err,
RadrootsCoreUnitConvertError::NotVolumeUnit {
- from: RadrootsCoreUnit::Each,
- to: RadrootsCoreUnit::VolumeMl
+ from: Unit::Each,
+ to: Unit::VolumeMl
}
);
- let err = convert_volume_decimal(
- common::dec("1"),
- RadrootsCoreUnit::VolumeMl,
- RadrootsCoreUnit::Each,
- )
- .unwrap_err();
+ let err = convert_volume_decimal(common::dec("1"), Unit::VolumeMl, Unit::Each).unwrap_err();
assert_eq!(
err,
RadrootsCoreUnitConvertError::NotVolumeUnit {
- from: RadrootsCoreUnit::VolumeMl,
- to: RadrootsCoreUnit::Each
+ from: Unit::VolumeMl,
+ to: Unit::Each
}
);
}
#[test]
fn convert_unit_decimal_converts_matching_dimensions() {
- use RadrootsCoreUnit::*;
+ use Unit::*;
let kg_to_g = convert_unit_decimal(common::dec("1"), MassKg, MassG).unwrap();
let l_to_ml = convert_unit_decimal(common::dec("2"), VolumeL, VolumeMl).unwrap();
let each_to_each = convert_unit_decimal(common::dec("3"), Each, Each).unwrap();
@@ -207,7 +186,7 @@ fn convert_unit_decimal_converts_matching_dimensions() {
#[test]
fn display_paths_for_unit_and_errors_are_exercised() {
- assert_eq!(RadrootsCoreUnit::MassOz.to_string(), "oz");
+ assert_eq!(Unit::MassOz.to_string(), "oz");
assert_eq!(
RadrootsCoreUnitParseError::UnknownUnit.to_string(),
"unknown unit string"
@@ -222,24 +201,24 @@ fn display_paths_for_unit_and_errors_are_exercised() {
);
assert_eq!(
RadrootsCoreUnitConvertError::NotMassUnit {
- from: RadrootsCoreUnit::Each,
- to: RadrootsCoreUnit::MassG
+ from: Unit::Each,
+ to: Unit::MassG
}
.to_string(),
"unit conversion requires mass units: each -> g"
);
assert_eq!(
RadrootsCoreUnitConvertError::NotVolumeUnit {
- from: RadrootsCoreUnit::Each,
- to: RadrootsCoreUnit::VolumeL
+ from: Unit::Each,
+ to: Unit::VolumeL
}
.to_string(),
"unit conversion requires volume units: each -> l"
);
assert_eq!(
RadrootsCoreUnitConvertError::NotConvertibleUnits {
- from: RadrootsCoreUnit::Each,
- to: RadrootsCoreUnit::MassG
+ from: Unit::Each,
+ to: Unit::MassG
}
.to_string(),
"unit conversion requires matching dimensions: each -> g"
@@ -248,17 +227,12 @@ fn display_paths_for_unit_and_errors_are_exercised() {
#[test]
fn convert_unit_decimal_rejects_mismatched_dimensions() {
- let err = convert_unit_decimal(
- common::dec("1"),
- RadrootsCoreUnit::Each,
- RadrootsCoreUnit::MassG,
- )
- .unwrap_err();
+ let err = convert_unit_decimal(common::dec("1"), Unit::Each, Unit::MassG).unwrap_err();
assert_eq!(
err,
RadrootsCoreUnitConvertError::NotConvertibleUnits {
- from: RadrootsCoreUnit::Each,
- to: RadrootsCoreUnit::MassG
+ from: Unit::Each,
+ to: Unit::MassG
}
);
}
@@ -266,19 +240,19 @@ fn convert_unit_decimal_rejects_mismatched_dimensions() {
#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip_for_unit_paths() {
- use RadrootsCoreUnit::*;
+ use Unit::*;
let all = [Each, MassKg, MassG, MassOz, MassLb, VolumeL, VolumeMl];
for unit in all {
let json = serde_json::to_string(&unit).unwrap();
- let back: RadrootsCoreUnit = serde_json::from_str(&json).unwrap();
+ let back: Unit = serde_json::from_str(&json).unwrap();
assert_eq!(back, unit);
}
- let back: RadrootsCoreUnit = serde_json::from_str("\"kg\"").unwrap();
- assert_eq!(back, RadrootsCoreUnit::MassKg);
- let unknown_err = serde_json::from_str::<RadrootsCoreUnit>("\"bogus\"").unwrap_err();
+ let back: Unit = serde_json::from_str("\"kg\"").unwrap();
+ assert_eq!(back, Unit::MassKg);
+ let unknown_err = serde_json::from_str::<Unit>("\"bogus\"").unwrap_err();
assert!(unknown_err.to_string().contains("unknown unit"));
- let err = serde_json::from_str::<RadrootsCoreUnit>("123").unwrap_err();
+ let err = serde_json::from_str::<Unit>("123").unwrap_err();
assert!(err.to_string().contains("invalid type"));
- let missing_err = serde_json::from_str::<RadrootsCoreUnit>("{}").unwrap_err();
+ let missing_err = serde_json::from_str::<Unit>("{}").unwrap_err();
assert!(!missing_err.to_string().is_empty());
}
diff --git a/crates/event_store/contracts/source_maintenance_v1.manifest.json b/crates/event_store/contracts/source_maintenance_v1.manifest.json
@@ -157,6 +157,55 @@
"hash_algorithm": "sha256_bytes_v1"
},
{
+ "role": "core_currency_value_authority",
+ "path": "crates/core/src/currency.rs",
+ "byte_length": 4095,
+ "sha256": "fdd7ccb88abdf7b91a362fdeeded752346331c5510ed1c769ec69a2780fa333a",
+ "hash_algorithm": "sha256_bytes_v1"
+ },
+ {
+ "role": "core_decimal_value_authority",
+ "path": "crates/core/src/decimal.rs",
+ "byte_length": 3851,
+ "sha256": "741c16a8cad7a769a7cf74458ef56141f04badb62de107966a9be85d241faa39",
+ "hash_algorithm": "sha256_bytes_v1"
+ },
+ {
+ "role": "core_money_value_authority",
+ "path": "crates/core/src/money.rs",
+ "byte_length": 6615,
+ "sha256": "8e830a3a01a2252d06275306848bf2389b5e4fb6a88bb85015bc6a072da969d0",
+ "hash_algorithm": "sha256_bytes_v1"
+ },
+ {
+ "role": "core_percent_value_authority",
+ "path": "crates/core/src/percent.rs",
+ "byte_length": 2266,
+ "sha256": "f0d7d9c66734666070620e95b9d46a22f5b21b881aa93a9a8b914fb2b5f86d69",
+ "hash_algorithm": "sha256_bytes_v1"
+ },
+ {
+ "role": "core_quantity_value_authority",
+ "path": "crates/core/src/quantity.rs",
+ "byte_length": 6189,
+ "sha256": "9b5450b602f6da4bf85e644bc362cec777638b4a95b6d4d4af791ec9f501d3ae",
+ "hash_algorithm": "sha256_bytes_v1"
+ },
+ {
+ "role": "core_quantity_price_value_authority",
+ "path": "crates/core/src/quantity_price.rs",
+ "byte_length": 5579,
+ "sha256": "166a3a6a43733dcafc39f917f166710fa24f408dbaf1c5133f9a51e5732d6d20",
+ "hash_algorithm": "sha256_bytes_v1"
+ },
+ {
+ "role": "core_unit_value_authority",
+ "path": "crates/core/src/unit.rs",
+ "byte_length": 9280,
+ "sha256": "736239f31fd0864fd1c1862aa6df49d56d4d0d8991ef6e7a25d83ab1b99a5896",
+ "hash_algorithm": "sha256_bytes_v1"
+ },
+ {
"role": "event_store_error_and_limits",
"path": "crates/event_store/src/error.rs",
"byte_length": 19421,
@@ -236,8 +285,8 @@
{
"role": "predecessor_successor_governance",
"path": "tools/xtask/src/contract/food_availability_projection.rs",
- "byte_length": 195036,
- "sha256": "d3c567ea3b4ea709723af2d5b6a2dc47993c6ba42c1d62895bd26fa101ebf829",
+ "byte_length": 194594,
+ "sha256": "4b2961fc69c8204ad5470c0e51c93533063e49d7a14da00a53598c3e8d0cdf6b",
"hash_algorithm": "sha256_bytes_v1"
},
{
@@ -250,15 +299,15 @@
{
"role": "source_maintenance_governance",
"path": "tools/xtask/src/contract/source_maintenance.rs",
- "byte_length": 176811,
- "sha256": "c9acc9934b3ce89505046049d4c125f4fde7d03224ffeeb0f22d10c7b22e1774",
+ "byte_length": 177996,
+ "sha256": "c309da38f12101d77c4de1caa49ef443252cac6238b49692182851c2cf894bda",
"hash_algorithm": "sha256_bytes_v1"
},
{
"role": "contract_command_authority",
"path": "tools/xtask/src/contract.rs",
- "byte_length": 500480,
- "sha256": "84739ad8b78bae49ea1f992672101bd83135415042cb22a85dbcbf5c878fc097",
+ "byte_length": 500241,
+ "sha256": "972e2a6b1099267e11d9a34e73fd38b20fc217a3dd79bd9a0f1f060b680ba2ba",
"hash_algorithm": "sha256_bytes_v1"
},
{
diff --git a/crates/event_store/contracts/source_maintenance_v1.manifest.sha256 b/crates/event_store/contracts/source_maintenance_v1.manifest.sha256
@@ -1 +1 @@
-004b0c8568e113063732c8f906673a38520717726ff22af7b4530780dbef3a08
+32670d9ee4b33052c41ce808b3d9ec8471dd67919ed415ce4f68ce9408ead11c
diff --git a/crates/event_store/src/generated/source_maintenance_manifest.rs b/crates/event_store/src/generated/source_maintenance_manifest.rs
@@ -1,8 +1,8 @@
// @generated by `cargo xtask contract source-maintenance-manifest --write`; do not edit.
-pub(crate) const SOURCE_MAINTENANCE_MANIFEST_JSON: &str = "{\n \"schema_version\": 1,\n \"contract_id\": \"radroots_event_store.source_maintenance_v1\",\n \"hook_id\": \"source_maintenance_v1\",\n \"manifest_schema\": {\n \"path\": \"crates/event_store/contracts/source_maintenance_v1.manifest.schema.json\",\n \"byte_length\": 12315,\n \"sha256\": \"ad4a6c8ae9488fc8033792bc6952af04687f312901c1847d8c668a62913bb642\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"predecessor\": {\n \"hook_id\": \"food_availability_projection_v1\",\n \"manifest\": {\n \"path\": \"crates/event_store/contracts/food_availability_projection_v1.manifest.json\",\n \"byte_length\": 17455,\n \"sha256\": \"33b93a3c87ce428e8aa6f5e92643c77203d9aa006c53ce96f3562fe6d68ffd23\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n },\n \"migration\": {\n \"version\": 4,\n \"name\": \"source_maintenance\",\n \"up\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.up.sql\",\n \"byte_length\": 19841,\n \"sha256\": \"425dc799f392b87f265a6fb81f89c4a1c7a5db8391ab0380970708cb9c66704d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"down\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.down.sql\",\n \"byte_length\": 5172,\n \"sha256\": \"fe44fd53c51545c08ea479b385e6781079dab70fc63da2a3c205d727a00ce860\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"schema_sha256\": \"d526d96ea02be12b4b0aed99e97cfdde17c4474ace67111506a7b900ee78b186\",\n \"catalog\": {\n \"objects\": [\n \"radroots_event_store_source_capacity_delete_guard\",\n \"radroots_event_store_source_capacity_insert_guard\",\n \"radroots_event_store_source_capacity_marker_close_guard\",\n \"radroots_event_store_source_capacity_update_guard\",\n \"radroots_event_store_source_capacity_v1\",\n \"radroots_event_store_source_generation_capacity_advance\",\n \"radroots_event_store_source_generation_capacity_guard\"\n ],\n \"replaced_objects\": [\n \"radroots_event_store_food_availability_image_delete_guard\",\n \"radroots_event_store_food_availability_projection_delete_guard\",\n \"radroots_event_store_source_rebuild_marker_insert_guard\"\n ],\n \"tables\": [\n \"radroots_event_store_source_capacity_v1\"\n ],\n \"fts5_tables\": []\n }\n },\n \"source_maintenance\": {\n \"version\": 1,\n \"event_contract_registry_version\": 7,\n \"capacity_authority_id\": \"radroots_event_store_source_capacity_v1\",\n \"accounting\": {\n \"algorithm\": \"sqlite_cast_blob_octet_sum_v1\",\n \"raw_event_columns\": [\n \"event_id\",\n \"pubkey\",\n \"tags_json\",\n \"content\",\n \"sig\",\n \"raw_json\"\n ],\n \"raw_tag_columns\": [\n \"event_id\",\n \"tag_name\",\n \"tag_value\",\n \"tag_json\"\n ],\n \"nullable_raw_tag_columns\": [\n \"tag_value\"\n ]\n },\n \"limits\": {\n \"raw_events\": 25000,\n \"raw_tags\": 250000,\n \"raw_event_text_bytes\": 67108864,\n \"raw_tag_text_bytes\": 33554432,\n \"retained_source_generations\": 8\n },\n \"reopen_validation\": {\n \"mode\": \"bounded_full_raw_recount_v1\",\n \"raw_event_rejection_scan_bound\": 25001,\n \"raw_tag_rejection_scan_bound\": 250001,\n \"generation_history_validation\": \"bounded_count_plus_active_ordinal_v1\",\n \"retained_generation_rejection_scan_bound\": 9\n },\n \"rebuild_seal\": {\n \"nip09_hook_id\": \"nip09_reconciliation_v1\",\n \"nip09_manifest_sha256\": \"74af832420ffbaa9805e89df3c0b34f126a443e1598f757e3372f407f9003b77\",\n \"food_hook_id\": \"food_availability_projection_v1\",\n \"food_manifest_sha256\": \"33b93a3c87ce428e8aa6f5e92643c77203d9aa006c53ce96f3562fe6d68ffd23\",\n \"food_scope_fingerprint_sha256\": \"8b63c5ddc48a2cc7db69295238b96d5f814dba50427c80b4d0079f061e6d3de0\",\n \"active_generation_authority\": \"radroots_event_store_source_state\",\n \"marker_close_authority\": \"radroots_event_store_source_capacity_marker_close_guard\"\n }\n },\n \"entry_points\": [\n {\n \"role\": \"migration_registry\",\n \"rust_path\": \"radroots_event_store::migrations::EVENT_STORE_MIGRATIONS[3]\"\n },\n {\n \"role\": \"migration_apply_hook\",\n \"rust_path\": \"radroots_event_store::schema::apply_migration_hook\"\n },\n {\n \"role\": \"migration_validation_hook\",\n \"rust_path\": \"radroots_event_store::schema::validate_migration_hook_state\"\n },\n {\n \"role\": \"capacity_query\",\n \"rust_path\": \"radroots_event_store::RadrootsEventStore::source_capacity_v1\"\n },\n {\n \"role\": \"raw_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_unique_raw_source_append_v1\"\n },\n {\n \"role\": \"raw_append_advance\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::advance_source_capacity_after_insert_v1\"\n },\n {\n \"role\": \"generation_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_source_generation_append_v1\"\n },\n {\n \"role\": \"generation_rebuild_bind\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::bind_source_capacity_to_generation_v1\"\n },\n {\n \"role\": \"sqlite_encoding_preflight\",\n \"rust_path\": \"radroots_event_store::store::validate_main_database_encoding\"\n },\n {\n \"role\": \"source_generation_history_rollback_guard\",\n \"rust_path\": \"radroots_event_store::schema::validate_rollback_preserves_source_generation_history\"\n },\n {\n \"role\": \"result_vector_executor\",\n \"rust_path\": \"source_maintenance_v1_result_vector\"\n }\n ],\n \"source_files\": [\n {\n \"role\": \"workspace_dependency_authority\",\n \"path\": \"Cargo.toml\",\n \"byte_length\": 11546,\n \"sha256\": \"0378afe281a46e02e83e128324efefc3da950abf3e1d3d06c75b628f69810bd2\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_error_and_limits\",\n \"path\": \"crates/event_store/src/error.rs\",\n \"byte_length\": 19421,\n \"sha256\": \"4772e041cb20a4963afb2f3159804c777e2f2be61bfdb6ee267e7a7c04258972\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"generated_descriptor_registration\",\n \"path\": \"crates/event_store/src/generated.rs\",\n \"byte_length\": 144,\n \"sha256\": \"6b0a8d6f249bd4fc3f878d37cb5e418680f0f1be2d9eec2518dedf03efc47121\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_surface\",\n \"path\": \"crates/event_store/src/lib.rs\",\n \"byte_length\": 3844,\n \"sha256\": \"3cd9653bcb752fb3c4442d4904b98a0a6208011a9a238125b7b7073d7f4e312b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"migration_registry\",\n \"path\": \"crates/event_store/src/migrations.rs\",\n \"byte_length\": 73585,\n \"sha256\": \"a47477d04759ec6e71d14d3d05459864eae78fce0e3c2481a1b03147f04637f7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_model_public_surface\",\n \"path\": \"crates/event_store/src/model.rs\",\n \"byte_length\": 33617,\n \"sha256\": \"79296b8f263aa06d17005795e4515f769f064ea6fd971eeb1296e1151debaf20\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_generation_rebuild_authority\",\n \"path\": \"crates/event_store/src/nip09/reconciliation_v1.rs\",\n \"byte_length\": 184407,\n \"sha256\": \"c455d40fc736e3db264f567c7809af7bd897d89be8a33dfb21667a6ef6b8d6c6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"schema_migration_and_reopen_authority\",\n \"path\": \"crates/event_store/src/schema.rs\",\n \"byte_length\": 146146,\n \"sha256\": \"93b060e80d3edd73f86208e4bf698fa9d53eaf1eeb04526c9261fb8b5726fb0d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_store_and_transaction_authority\",\n \"path\": \"crates/event_store/src/store.rs\",\n \"byte_length\": 394574,\n \"sha256\": \"db57dc3e35e64c7194683142fe55edba853671a829269449dd2273056dfc3a0e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"raw_ingest_capacity_authority\",\n \"path\": \"crates/event_store/src/store/protocol_reconciliation_v1.rs\",\n \"byte_length\": 30140,\n \"sha256\": \"210112eeaa6975a3b4fbb97d5c52588f8c6d8d07975e531d39737fd11235de51\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_runtime\",\n \"path\": \"crates/event_store/src/source_maintenance_v1.rs\",\n \"byte_length\": 51756,\n \"sha256\": \"f8d5b62f0613104aa86658d5bf1baade92c7df83f00ef0cddadd734b9797afca\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"artifact_transaction_authority\",\n \"path\": \"tools/xtask/src/contract/artifact_bundle.rs\",\n \"byte_length\": 38279,\n \"sha256\": \"f326ea57b56d40135f95b6b1e15961f66eed363337180a6d12a5ea903e1a9a29\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_successor_governance\",\n \"path\": \"tools/xtask/src/contract/food_availability_projection.rs\",\n \"byte_length\": 195036,\n \"sha256\": \"d3c567ea3b4ea709723af2d5b6a2dc47993c6ba42c1d62895bd26fa101ebf829\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"transitive_predecessor_membership_governance\",\n \"path\": \"tools/xtask/src/contract/nip09_reconciliation.rs\",\n \"byte_length\": 835585,\n \"sha256\": \"51d524cb00d2d96dc0da35fc9133c54f2e5328a830d56b8d5e83a7f1e9654ddc\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_governance\",\n \"path\": \"tools/xtask/src/contract/source_maintenance.rs\",\n \"byte_length\": 176811,\n \"sha256\": \"c9acc9934b3ce89505046049d4c125f4fde7d03224ffeeb0f22d10c7b22e1774\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"contract_command_authority\",\n \"path\": \"tools/xtask/src/contract.rs\",\n \"byte_length\": 500480,\n \"sha256\": \"84739ad8b78bae49ea1f992672101bd83135415042cb22a85dbcbf5c878fc097\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"xtask_dispatch_and_release_preflight\",\n \"path\": \"tools/xtask/src/main.rs\",\n \"byte_length\": 14976,\n \"sha256\": \"42b59a8576e4f86b091941a64349ac9eaa20b1e3b52aef367bb3d5947d8ccd1d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n ],\n \"public_api\": {\n \"inherited_predecessor_symbols\": [\n \"RADROOTS_ADDRESSABLE_TRANSITION_CURSOR_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_D_TAG_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_FEED_VERSION_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_LIMIT_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_RAW_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_SCAN_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_SCOPE_KIND_MAX_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_APPLY_PAGE_LIMIT_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_VERSION_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_BYTES_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_TERMS_V1\",\n \"RadrootsAddressableTransitionCauseV1\",\n \"RadrootsAddressableTransitionCoordinateV1\",\n \"RadrootsAddressableTransitionCursorV1\",\n \"RadrootsAddressableTransitionEventReferenceV1\",\n \"RadrootsAddressableTransitionOriginV1\",\n \"RadrootsAddressableTransitionPageV1\",\n \"RadrootsAddressableTransitionRawHeadDecisionV1\",\n \"RadrootsAddressableTransitionScopeFingerprintV1\",\n \"RadrootsAddressableTransitionScopeV1\",\n \"RadrootsAddressableTransitionV1\",\n \"RadrootsAddressableTransitionVisibilityV1\",\n \"RadrootsCurrentEventVisibilityV1\",\n \"RadrootsCurrentVisibilityDecisionV1\",\n \"RadrootsFoodAvailabilitySearchQueryV1\",\n \"RadrootsFoodAvailabilityStatusFilterV1\",\n \"RadrootsNip09SuppressionEvidenceV1\",\n \"RadrootsNip09SuppressionOutcome\",\n \"RadrootsNip09SuppressionReason\",\n \"RadrootsStoreProducedCanonicalEventV1\",\n \"RadrootsStoredFoodAvailabilityImageV1\",\n \"RadrootsStoredFoodAvailabilityV1\"\n ],\n \"added_symbols\": [\n \"RADROOTS_EVENT_STORE_RAW_EVENT_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_EVENT_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RETAINED_SOURCE_GENERATION_LIMIT_V1\",\n \"RadrootsEventStoreSourceCapacityResourceV1\",\n \"RadrootsEventStoreSourceCapacityV1\"\n ],\n \"methods\": [\n \"RadrootsEventStore::source_capacity_v1\",\n \"RadrootsEventStoreSourceCapacityResourceV1::as_str\",\n \"RadrootsEventStoreSourceCapacityV1::source_generation\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_high_water_seq\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_count\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_limit\"\n ],\n \"error_variants\": [\n \"SourceCapacityExceeded\",\n \"SourceGenerationHistoryLimitReached\",\n \"PersistedEphemeralRawEvent\",\n \"SourceCapacityStateDrift\",\n \"SqliteMainDatabaseEncodingNotUtf8\",\n \"RollbackWouldDiscardSourceGenerationHistory\"\n ],\n \"removed_symbols\": [\n \"RadrootsEventStoreReconciliationResource\",\n \"RadrootsEventStoreError::ReconciliationCapacityExceeded\"\n ],\n \"breaking_replacements\": [\n {\n \"removed\": \"RadrootsEventStoreReconciliationResource\",\n \"replacement\": \"RadrootsEventStoreSourceCapacityResourceV1\"\n },\n {\n \"removed\": \"RadrootsEventStoreError::ReconciliationCapacityExceeded\",\n \"replacement\": \"RadrootsEventStoreError::SourceCapacityExceeded\"\n }\n ]\n },\n \"result_vector\": {\n \"canonical_path\": \"contracts/conformance/vectors/event_store/source_maintenance.v1.json\",\n \"mirror_path\": \"crates/event_store/tests/fixtures/source_maintenance.v1.json\",\n \"byte_length\": 16253,\n \"sha256\": \"997aba2604a2b9d199fb87dc9d07942ca50d91863aeadcf3eeacf16d191dd71f\",\n \"hash_algorithm\": \"sha256_bytes_v1\",\n \"executor_id\": \"radroots_event_store.source_maintenance_v1.result_vector_executor.v1\",\n \"executor_path\": \"crates/event_store/tests/source_maintenance_v1_result_vector.rs\",\n \"executor_test\": \"source_maintenance_v1_result_vector\",\n \"executor_byte_length\": 23510,\n \"executor_sha256\": \"a7487afdfe19fc5fc794811d0f0e6035203e1aabcf0a33a1d398f6b3555d38f3\",\n \"executor_hash_algorithm\": \"sha256_bytes_v1\"\n }\n}\n";
-pub(crate) const SOURCE_MAINTENANCE_MANIFEST_BYTE_LENGTH: usize = 14459;
+pub(crate) const SOURCE_MAINTENANCE_MANIFEST_JSON: &str = "{\n \"schema_version\": 1,\n \"contract_id\": \"radroots_event_store.source_maintenance_v1\",\n \"hook_id\": \"source_maintenance_v1\",\n \"manifest_schema\": {\n \"path\": \"crates/event_store/contracts/source_maintenance_v1.manifest.schema.json\",\n \"byte_length\": 12315,\n \"sha256\": \"ad4a6c8ae9488fc8033792bc6952af04687f312901c1847d8c668a62913bb642\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"predecessor\": {\n \"hook_id\": \"food_availability_projection_v1\",\n \"manifest\": {\n \"path\": \"crates/event_store/contracts/food_availability_projection_v1.manifest.json\",\n \"byte_length\": 17455,\n \"sha256\": \"33b93a3c87ce428e8aa6f5e92643c77203d9aa006c53ce96f3562fe6d68ffd23\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n },\n \"migration\": {\n \"version\": 4,\n \"name\": \"source_maintenance\",\n \"up\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.up.sql\",\n \"byte_length\": 19841,\n \"sha256\": \"425dc799f392b87f265a6fb81f89c4a1c7a5db8391ab0380970708cb9c66704d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"down\": {\n \"path\": \"crates/event_store/migrations/0004_source_maintenance.down.sql\",\n \"byte_length\": 5172,\n \"sha256\": \"fe44fd53c51545c08ea479b385e6781079dab70fc63da2a3c205d727a00ce860\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n \"schema_sha256\": \"d526d96ea02be12b4b0aed99e97cfdde17c4474ace67111506a7b900ee78b186\",\n \"catalog\": {\n \"objects\": [\n \"radroots_event_store_source_capacity_delete_guard\",\n \"radroots_event_store_source_capacity_insert_guard\",\n \"radroots_event_store_source_capacity_marker_close_guard\",\n \"radroots_event_store_source_capacity_update_guard\",\n \"radroots_event_store_source_capacity_v1\",\n \"radroots_event_store_source_generation_capacity_advance\",\n \"radroots_event_store_source_generation_capacity_guard\"\n ],\n \"replaced_objects\": [\n \"radroots_event_store_food_availability_image_delete_guard\",\n \"radroots_event_store_food_availability_projection_delete_guard\",\n \"radroots_event_store_source_rebuild_marker_insert_guard\"\n ],\n \"tables\": [\n \"radroots_event_store_source_capacity_v1\"\n ],\n \"fts5_tables\": []\n }\n },\n \"source_maintenance\": {\n \"version\": 1,\n \"event_contract_registry_version\": 7,\n \"capacity_authority_id\": \"radroots_event_store_source_capacity_v1\",\n \"accounting\": {\n \"algorithm\": \"sqlite_cast_blob_octet_sum_v1\",\n \"raw_event_columns\": [\n \"event_id\",\n \"pubkey\",\n \"tags_json\",\n \"content\",\n \"sig\",\n \"raw_json\"\n ],\n \"raw_tag_columns\": [\n \"event_id\",\n \"tag_name\",\n \"tag_value\",\n \"tag_json\"\n ],\n \"nullable_raw_tag_columns\": [\n \"tag_value\"\n ]\n },\n \"limits\": {\n \"raw_events\": 25000,\n \"raw_tags\": 250000,\n \"raw_event_text_bytes\": 67108864,\n \"raw_tag_text_bytes\": 33554432,\n \"retained_source_generations\": 8\n },\n \"reopen_validation\": {\n \"mode\": \"bounded_full_raw_recount_v1\",\n \"raw_event_rejection_scan_bound\": 25001,\n \"raw_tag_rejection_scan_bound\": 250001,\n \"generation_history_validation\": \"bounded_count_plus_active_ordinal_v1\",\n \"retained_generation_rejection_scan_bound\": 9\n },\n \"rebuild_seal\": {\n \"nip09_hook_id\": \"nip09_reconciliation_v1\",\n \"nip09_manifest_sha256\": \"74af832420ffbaa9805e89df3c0b34f126a443e1598f757e3372f407f9003b77\",\n \"food_hook_id\": \"food_availability_projection_v1\",\n \"food_manifest_sha256\": \"33b93a3c87ce428e8aa6f5e92643c77203d9aa006c53ce96f3562fe6d68ffd23\",\n \"food_scope_fingerprint_sha256\": \"8b63c5ddc48a2cc7db69295238b96d5f814dba50427c80b4d0079f061e6d3de0\",\n \"active_generation_authority\": \"radroots_event_store_source_state\",\n \"marker_close_authority\": \"radroots_event_store_source_capacity_marker_close_guard\"\n }\n },\n \"entry_points\": [\n {\n \"role\": \"migration_registry\",\n \"rust_path\": \"radroots_event_store::migrations::EVENT_STORE_MIGRATIONS[3]\"\n },\n {\n \"role\": \"migration_apply_hook\",\n \"rust_path\": \"radroots_event_store::schema::apply_migration_hook\"\n },\n {\n \"role\": \"migration_validation_hook\",\n \"rust_path\": \"radroots_event_store::schema::validate_migration_hook_state\"\n },\n {\n \"role\": \"capacity_query\",\n \"rust_path\": \"radroots_event_store::RadrootsEventStore::source_capacity_v1\"\n },\n {\n \"role\": \"raw_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_unique_raw_source_append_v1\"\n },\n {\n \"role\": \"raw_append_advance\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::advance_source_capacity_after_insert_v1\"\n },\n {\n \"role\": \"generation_append_preflight\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::preflight_source_generation_append_v1\"\n },\n {\n \"role\": \"generation_rebuild_bind\",\n \"rust_path\": \"radroots_event_store::source_maintenance_v1::bind_source_capacity_to_generation_v1\"\n },\n {\n \"role\": \"sqlite_encoding_preflight\",\n \"rust_path\": \"radroots_event_store::store::validate_main_database_encoding\"\n },\n {\n \"role\": \"source_generation_history_rollback_guard\",\n \"rust_path\": \"radroots_event_store::schema::validate_rollback_preserves_source_generation_history\"\n },\n {\n \"role\": \"result_vector_executor\",\n \"rust_path\": \"source_maintenance_v1_result_vector\"\n }\n ],\n \"source_files\": [\n {\n \"role\": \"workspace_dependency_authority\",\n \"path\": \"Cargo.toml\",\n \"byte_length\": 11546,\n \"sha256\": \"0378afe281a46e02e83e128324efefc3da950abf3e1d3d06c75b628f69810bd2\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_currency_value_authority\",\n \"path\": \"crates/core/src/currency.rs\",\n \"byte_length\": 4095,\n \"sha256\": \"fdd7ccb88abdf7b91a362fdeeded752346331c5510ed1c769ec69a2780fa333a\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_decimal_value_authority\",\n \"path\": \"crates/core/src/decimal.rs\",\n \"byte_length\": 3851,\n \"sha256\": \"741c16a8cad7a769a7cf74458ef56141f04badb62de107966a9be85d241faa39\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_money_value_authority\",\n \"path\": \"crates/core/src/money.rs\",\n \"byte_length\": 6615,\n \"sha256\": \"8e830a3a01a2252d06275306848bf2389b5e4fb6a88bb85015bc6a072da969d0\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_percent_value_authority\",\n \"path\": \"crates/core/src/percent.rs\",\n \"byte_length\": 2266,\n \"sha256\": \"f0d7d9c66734666070620e95b9d46a22f5b21b881aa93a9a8b914fb2b5f86d69\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_quantity_value_authority\",\n \"path\": \"crates/core/src/quantity.rs\",\n \"byte_length\": 6189,\n \"sha256\": \"9b5450b602f6da4bf85e644bc362cec777638b4a95b6d4d4af791ec9f501d3ae\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_quantity_price_value_authority\",\n \"path\": \"crates/core/src/quantity_price.rs\",\n \"byte_length\": 5579,\n \"sha256\": \"166a3a6a43733dcafc39f917f166710fa24f408dbaf1c5133f9a51e5732d6d20\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"core_unit_value_authority\",\n \"path\": \"crates/core/src/unit.rs\",\n \"byte_length\": 9280,\n \"sha256\": \"736239f31fd0864fd1c1862aa6df49d56d4d0d8991ef6e7a25d83ab1b99a5896\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"event_store_error_and_limits\",\n \"path\": \"crates/event_store/src/error.rs\",\n \"byte_length\": 19421,\n \"sha256\": \"4772e041cb20a4963afb2f3159804c777e2f2be61bfdb6ee267e7a7c04258972\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"generated_descriptor_registration\",\n \"path\": \"crates/event_store/src/generated.rs\",\n \"byte_length\": 144,\n \"sha256\": \"6b0a8d6f249bd4fc3f878d37cb5e418680f0f1be2d9eec2518dedf03efc47121\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_surface\",\n \"path\": \"crates/event_store/src/lib.rs\",\n \"byte_length\": 3844,\n \"sha256\": \"3cd9653bcb752fb3c4442d4904b98a0a6208011a9a238125b7b7073d7f4e312b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"migration_registry\",\n \"path\": \"crates/event_store/src/migrations.rs\",\n \"byte_length\": 73585,\n \"sha256\": \"a47477d04759ec6e71d14d3d05459864eae78fce0e3c2481a1b03147f04637f7\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_model_public_surface\",\n \"path\": \"crates/event_store/src/model.rs\",\n \"byte_length\": 33617,\n \"sha256\": \"79296b8f263aa06d17005795e4515f769f064ea6fd971eeb1296e1151debaf20\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_generation_rebuild_authority\",\n \"path\": \"crates/event_store/src/nip09/reconciliation_v1.rs\",\n \"byte_length\": 184407,\n \"sha256\": \"c455d40fc736e3db264f567c7809af7bd897d89be8a33dfb21667a6ef6b8d6c6\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"schema_migration_and_reopen_authority\",\n \"path\": \"crates/event_store/src/schema.rs\",\n \"byte_length\": 146146,\n \"sha256\": \"93b060e80d3edd73f86208e4bf698fa9d53eaf1eeb04526c9261fb8b5726fb0d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"public_store_and_transaction_authority\",\n \"path\": \"crates/event_store/src/store.rs\",\n \"byte_length\": 394574,\n \"sha256\": \"db57dc3e35e64c7194683142fe55edba853671a829269449dd2273056dfc3a0e\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"raw_ingest_capacity_authority\",\n \"path\": \"crates/event_store/src/store/protocol_reconciliation_v1.rs\",\n \"byte_length\": 30140,\n \"sha256\": \"210112eeaa6975a3b4fbb97d5c52588f8c6d8d07975e531d39737fd11235de51\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_runtime\",\n \"path\": \"crates/event_store/src/source_maintenance_v1.rs\",\n \"byte_length\": 51756,\n \"sha256\": \"f8d5b62f0613104aa86658d5bf1baade92c7df83f00ef0cddadd734b9797afca\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"artifact_transaction_authority\",\n \"path\": \"tools/xtask/src/contract/artifact_bundle.rs\",\n \"byte_length\": 38279,\n \"sha256\": \"f326ea57b56d40135f95b6b1e15961f66eed363337180a6d12a5ea903e1a9a29\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"predecessor_successor_governance\",\n \"path\": \"tools/xtask/src/contract/food_availability_projection.rs\",\n \"byte_length\": 194594,\n \"sha256\": \"4b2961fc69c8204ad5470c0e51c93533063e49d7a14da00a53598c3e8d0cdf6b\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"transitive_predecessor_membership_governance\",\n \"path\": \"tools/xtask/src/contract/nip09_reconciliation.rs\",\n \"byte_length\": 835585,\n \"sha256\": \"51d524cb00d2d96dc0da35fc9133c54f2e5328a830d56b8d5e83a7f1e9654ddc\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"source_maintenance_governance\",\n \"path\": \"tools/xtask/src/contract/source_maintenance.rs\",\n \"byte_length\": 177996,\n \"sha256\": \"c309da38f12101d77c4de1caa49ef443252cac6238b49692182851c2cf894bda\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"contract_command_authority\",\n \"path\": \"tools/xtask/src/contract.rs\",\n \"byte_length\": 500241,\n \"sha256\": \"972e2a6b1099267e11d9a34e73fd38b20fc217a3dd79bd9a0f1f060b680ba2ba\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n },\n {\n \"role\": \"xtask_dispatch_and_release_preflight\",\n \"path\": \"tools/xtask/src/main.rs\",\n \"byte_length\": 14976,\n \"sha256\": \"42b59a8576e4f86b091941a64349ac9eaa20b1e3b52aef367bb3d5947d8ccd1d\",\n \"hash_algorithm\": \"sha256_bytes_v1\"\n }\n ],\n \"public_api\": {\n \"inherited_predecessor_symbols\": [\n \"RADROOTS_ADDRESSABLE_TRANSITION_CURSOR_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_D_TAG_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_FEED_VERSION_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_LIMIT_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_RAW_JSON_MAX_BYTES_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_PAGE_SCAN_MAX_V1\",\n \"RADROOTS_ADDRESSABLE_TRANSITION_SCOPE_KIND_MAX_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_APPLY_PAGE_LIMIT_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_PROJECTION_VERSION_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_BYTES_V1\",\n \"RADROOTS_FOOD_AVAILABILITY_SEARCH_QUERY_MAX_TERMS_V1\",\n \"RadrootsAddressableTransitionCauseV1\",\n \"RadrootsAddressableTransitionCoordinateV1\",\n \"RadrootsAddressableTransitionCursorV1\",\n \"RadrootsAddressableTransitionEventReferenceV1\",\n \"RadrootsAddressableTransitionOriginV1\",\n \"RadrootsAddressableTransitionPageV1\",\n \"RadrootsAddressableTransitionRawHeadDecisionV1\",\n \"RadrootsAddressableTransitionScopeFingerprintV1\",\n \"RadrootsAddressableTransitionScopeV1\",\n \"RadrootsAddressableTransitionV1\",\n \"RadrootsAddressableTransitionVisibilityV1\",\n \"RadrootsCurrentEventVisibilityV1\",\n \"RadrootsCurrentVisibilityDecisionV1\",\n \"RadrootsFoodAvailabilitySearchQueryV1\",\n \"RadrootsFoodAvailabilityStatusFilterV1\",\n \"RadrootsNip09SuppressionEvidenceV1\",\n \"RadrootsNip09SuppressionOutcome\",\n \"RadrootsNip09SuppressionReason\",\n \"RadrootsStoreProducedCanonicalEventV1\",\n \"RadrootsStoredFoodAvailabilityImageV1\",\n \"RadrootsStoredFoodAvailabilityV1\"\n ],\n \"added_symbols\": [\n \"RADROOTS_EVENT_STORE_RAW_EVENT_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_EVENT_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_COUNT_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RAW_TAG_TEXT_BYTES_LIMIT_V1\",\n \"RADROOTS_EVENT_STORE_RETAINED_SOURCE_GENERATION_LIMIT_V1\",\n \"RadrootsEventStoreSourceCapacityResourceV1\",\n \"RadrootsEventStoreSourceCapacityV1\"\n ],\n \"methods\": [\n \"RadrootsEventStore::source_capacity_v1\",\n \"RadrootsEventStoreSourceCapacityResourceV1::as_str\",\n \"RadrootsEventStoreSourceCapacityV1::source_generation\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_count\",\n \"RadrootsEventStoreSourceCapacityV1::raw_event_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_tag_text_bytes\",\n \"RadrootsEventStoreSourceCapacityV1::raw_high_water_seq\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_count\",\n \"RadrootsEventStoreSourceCapacityV1::retained_generation_limit\"\n ],\n \"error_variants\": [\n \"SourceCapacityExceeded\",\n \"SourceGenerationHistoryLimitReached\",\n \"PersistedEphemeralRawEvent\",\n \"SourceCapacityStateDrift\",\n \"SqliteMainDatabaseEncodingNotUtf8\",\n \"RollbackWouldDiscardSourceGenerationHistory\"\n ],\n \"removed_symbols\": [\n \"RadrootsEventStoreReconciliationResource\",\n \"RadrootsEventStoreError::ReconciliationCapacityExceeded\"\n ],\n \"breaking_replacements\": [\n {\n \"removed\": \"RadrootsEventStoreReconciliationResource\",\n \"replacement\": \"RadrootsEventStoreSourceCapacityResourceV1\"\n },\n {\n \"removed\": \"RadrootsEventStoreError::ReconciliationCapacityExceeded\",\n \"replacement\": \"RadrootsEventStoreError::SourceCapacityExceeded\"\n }\n ]\n },\n \"result_vector\": {\n \"canonical_path\": \"contracts/conformance/vectors/event_store/source_maintenance.v1.json\",\n \"mirror_path\": \"crates/event_store/tests/fixtures/source_maintenance.v1.json\",\n \"byte_length\": 16253,\n \"sha256\": \"997aba2604a2b9d199fb87dc9d07942ca50d91863aeadcf3eeacf16d191dd71f\",\n \"hash_algorithm\": \"sha256_bytes_v1\",\n \"executor_id\": \"radroots_event_store.source_maintenance_v1.result_vector_executor.v1\",\n \"executor_path\": \"crates/event_store/tests/source_maintenance_v1_result_vector.rs\",\n \"executor_test\": \"source_maintenance_v1_result_vector\",\n \"executor_byte_length\": 23510,\n \"executor_sha256\": \"a7487afdfe19fc5fc794811d0f0e6035203e1aabcf0a33a1d398f6b3555d38f3\",\n \"executor_hash_algorithm\": \"sha256_bytes_v1\"\n }\n}\n";
+pub(crate) const SOURCE_MAINTENANCE_MANIFEST_BYTE_LENGTH: usize = 16259;
pub(crate) const SOURCE_MAINTENANCE_MANIFEST_SHA256: &str =
- "004b0c8568e113063732c8f906673a38520717726ff22af7b4530780dbef3a08";
+ "32670d9ee4b33052c41ce808b3d9ec8471dd67919ed415ce4f68ce9408ead11c";
pub(crate) const SOURCE_MAINTENANCE_MANIFEST_SCHEMA_VERSION: u32 = 1;
pub(crate) const SOURCE_MAINTENANCE_CONTRACT_ID: &str =
"radroots_event_store.source_maintenance_v1";
diff --git a/tools/xtask/src/contract.rs b/tools/xtask/src/contract.rs
@@ -8086,7 +8086,7 @@ fn validate_required_coverage_summary_with_policy(
Ok(())
}
-const CORE_UNIT_DIMENSION_ENUM: &str = "RadrootsCoreUnitDimension";
+const CORE_UNIT_DIMENSION_ENUM: &str = "UnitDimension";
const CORE_UNIT_DIMENSION_ORDER: [&str; 3] = ["Count", "Mass", "Volume"];
fn extract_enum_body<'a>(source: &'a str, enum_name: &str) -> Result<&'a str, String> {
@@ -9414,7 +9414,7 @@ version = "1.0.0"
);
write_file(
&root.join("crates").join("core").join("src").join("unit.rs"),
- r#"pub enum RadrootsCoreUnitDimension {
+ r#"pub enum UnitDimension {
Count,
Mass,
Volume,
@@ -11208,13 +11208,13 @@ crates = ["radroots_a", "radroots_b", "radroots_c", "radroots_d", "radroots_e"]
#[test]
fn parses_enum_variants_in_declared_order() {
let source = r#"
-pub enum RadrootsCoreUnitDimension {
+pub enum UnitDimension {
Count,
Mass,
Volume,
}
"#;
- let enum_body = extract_enum_body(source, "RadrootsCoreUnitDimension").expect("enum body");
+ let enum_body = extract_enum_body(source, "UnitDimension").expect("enum body");
let variants = parse_enum_variants(enum_body);
assert_eq!(variants, vec!["Count", "Mass", "Volume"]);
}
@@ -11222,13 +11222,13 @@ pub enum RadrootsCoreUnitDimension {
#[test]
fn fails_when_enum_order_does_not_match_contract() {
let source = r#"
-pub enum RadrootsCoreUnitDimension {
+pub enum UnitDimension {
Mass,
Count,
Volume,
}
"#;
- let enum_body = extract_enum_body(source, "RadrootsCoreUnitDimension").expect("enum body");
+ let enum_body = extract_enum_body(source, "UnitDimension").expect("enum body");
let variants = parse_enum_variants(enum_body);
let expected = CORE_UNIT_DIMENSION_ORDER
.iter()
@@ -11898,22 +11898,17 @@ members = ["crates/a", "crates/b"]
#[test]
fn enum_extract_and_parse_error_paths_are_reported() {
- let missing = extract_enum_body("pub struct X;", "RadrootsCoreUnitDimension")
- .expect_err("missing enum");
+ let missing =
+ extract_enum_body("pub struct X;", "UnitDimension").expect_err("missing enum");
assert!(missing.contains("missing enum"));
- let missing_brace = extract_enum_body(
- "pub enum RadrootsCoreUnitDimension",
- "RadrootsCoreUnitDimension",
- )
- .expect_err("missing opening brace");
+ let missing_brace = extract_enum_body("pub enum UnitDimension", "UnitDimension")
+ .expect_err("missing opening brace");
assert!(missing_brace.contains("missing opening brace"));
- let missing_close = extract_enum_body(
- "pub enum RadrootsCoreUnitDimension { Count, Mass",
- "RadrootsCoreUnitDimension",
- )
- .expect_err("missing closing brace");
+ let missing_close =
+ extract_enum_body("pub enum UnitDimension { Count, Mass", "UnitDimension")
+ .expect_err("missing closing brace");
assert!(missing_close.contains("missing closing brace"));
let variants = parse_enum_variants(
@@ -11928,8 +11923,8 @@ members = ["crates/a", "crates/b"]
assert_eq!(variants, vec!["Count".to_string()]);
let nested = extract_enum_body(
- "pub enum RadrootsCoreUnitDimension { Count = { 1 }, Mass = 2 }",
- "RadrootsCoreUnitDimension",
+ "pub enum UnitDimension { Count = { 1 }, Mass = 2 }",
+ "UnitDimension",
)
.expect("nested braces in enum body");
assert!(nested.contains("Count"));
@@ -13631,7 +13626,7 @@ requires_release_notes = true
let bundle = load_contract_bundle(&root).expect("load bundle");
write_file(
&root.join("crates").join("core").join("src").join("unit.rs"),
- r#"pub enum RadrootsCoreUnitDimension {
+ r#"pub enum UnitDimension {
Mass,
Count,
Volume,
@@ -13643,7 +13638,7 @@ Volume,
write_file(
&root.join("crates").join("core").join("src").join("unit.rs"),
- r#"pub enum RadrootsCoreUnitDimension {
+ r#"pub enum UnitDimension {
Count,
Mass,
Volume,
@@ -13794,7 +13789,7 @@ readme = { workspace = true }
.join("core")
.join("src")
.join("unit.rs"),
- r#"pub enum RadrootsCoreUnitDimension {
+ r#"pub enum UnitDimension {
Mass,
Count,
Volume,
diff --git a/tools/xtask/src/contract/food_availability_projection.rs b/tools/xtask/src/contract/food_availability_projection.rs
@@ -3996,18 +3996,8 @@ mod tests {
#[test]
fn downstream_nip09_only_supersession_is_transitively_validated() {
- const SOURCE_MAINTENANCE_SUPERSEDED_PATHS: &[&str] = &[
- "Cargo.toml",
- "crates/event_store/src/error.rs",
- "crates/event_store/src/generated.rs",
- "crates/event_store/src/lib.rs",
- "crates/event_store/src/migrations.rs",
- "crates/event_store/src/model.rs",
- "crates/event_store/src/nip09/reconciliation_v1.rs",
- "crates/event_store/src/schema.rs",
- "crates/event_store/src/store.rs",
- "crates/event_store/src/store/protocol_reconciliation_v1.rs",
- ];
+ let source_maintenance_superseded_paths =
+ super::super::source_maintenance::predecessor_superseded_source_paths();
let root = repository_root();
let (food_paths, nip09_paths) = partition_downstream_predecessor_supersessions(
@@ -4028,11 +4018,11 @@ mod tests {
);
validate_food_availability_projection_predecessor_production_sources_under_lock(
&root,
- SOURCE_MAINTENANCE_SUPERSEDED_PATHS,
+ source_maintenance_superseded_paths,
)
.expect("Food and transitive NIP-09 successor source coverage");
- let mut duplicate = SOURCE_MAINTENANCE_SUPERSEDED_PATHS.to_vec();
+ let mut duplicate = source_maintenance_superseded_paths.to_vec();
duplicate.push("crates/event_store/src/store/protocol_reconciliation_v1.rs");
let error =
validate_food_availability_projection_predecessor_production_sources_under_lock(
@@ -4041,7 +4031,7 @@ mod tests {
.expect_err("duplicate transitive supersession must fail");
assert!(error.contains("must be unique"), "{error}");
- let mut unknown = SOURCE_MAINTENANCE_SUPERSEDED_PATHS.to_vec();
+ let mut unknown = source_maintenance_superseded_paths.to_vec();
unknown.push("crates/event_store/src/store/not_predecessor_bound.rs");
let error =
validate_food_availability_projection_predecessor_production_sources_under_lock(
diff --git a/tools/xtask/src/contract/source_maintenance.rs b/tools/xtask/src/contract/source_maintenance.rs
@@ -247,6 +247,34 @@ const SOURCE_SPECS: &[SourceSpec] = &[
path: "Cargo.toml",
},
SourceSpec {
+ role: "core_currency_value_authority",
+ path: "crates/core/src/currency.rs",
+ },
+ SourceSpec {
+ role: "core_decimal_value_authority",
+ path: "crates/core/src/decimal.rs",
+ },
+ SourceSpec {
+ role: "core_money_value_authority",
+ path: "crates/core/src/money.rs",
+ },
+ SourceSpec {
+ role: "core_percent_value_authority",
+ path: "crates/core/src/percent.rs",
+ },
+ SourceSpec {
+ role: "core_quantity_value_authority",
+ path: "crates/core/src/quantity.rs",
+ },
+ SourceSpec {
+ role: "core_quantity_price_value_authority",
+ path: "crates/core/src/quantity_price.rs",
+ },
+ SourceSpec {
+ role: "core_unit_value_authority",
+ path: "crates/core/src/unit.rs",
+ },
+ SourceSpec {
role: "event_store_error_and_limits",
path: "crates/event_store/src/error.rs",
},
@@ -319,6 +347,13 @@ pub(super) fn source_contract_fixture_source_paths() -> Vec<&'static str> {
const PREDECESSOR_SUPERSEDED_SOURCE_PATHS: &[&str] = &[
"Cargo.toml",
+ "crates/core/src/currency.rs",
+ "crates/core/src/decimal.rs",
+ "crates/core/src/money.rs",
+ "crates/core/src/percent.rs",
+ "crates/core/src/quantity.rs",
+ "crates/core/src/quantity_price.rs",
+ "crates/core/src/unit.rs",
"crates/event_store/src/error.rs",
"crates/event_store/src/generated.rs",
"crates/event_store/src/lib.rs",
@@ -330,6 +365,11 @@ const PREDECESSOR_SUPERSEDED_SOURCE_PATHS: &[&str] = &[
"crates/event_store/src/store/protocol_reconciliation_v1.rs",
];
+#[cfg(test)]
+pub(super) fn predecessor_superseded_source_paths() -> &'static [&'static str] {
+ PREDECESSOR_SUPERSEDED_SOURCE_PATHS
+}
+
const GENERATED_ARTIFACT_PATHS: &[&str] = &[
MANIFEST_RELATIVE,
MANIFEST_SCHEMA_RELATIVE,