lib.rs (16977B)
1 //! Private inventory for canonical native trade bindings. 2 //! 3 //! The SDK generator authenticates the reviewed mapping against final 4 //! `radroots_trade`, `radroots_event`, and `radroots_core` owners. This crate 5 //! intentionally does not activate code generation in a public runtime crate. 6 7 #![cfg_attr(coverage_nightly, feature(coverage_attribute))] 8 9 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 10 pub enum TradeTypeDisposition { 11 SourceTradeRoot, 12 SourceTradeSupport, 13 EventsBindingImport, 14 SdkLocalPackageShape, 15 } 16 17 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 18 pub struct TradeTypeInventoryEntry { 19 pub export_name: &'static str, 20 pub disposition: TradeTypeDisposition, 21 } 22 23 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 24 pub enum TradeLargeIntegerPolicy { 25 JsonNumberSafeCount, 26 DecimalStringU64, 27 } 28 29 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 30 pub struct TradeLargeIntegerPolicyEntry { 31 pub type_name: &'static str, 32 pub field_name: &'static str, 33 pub policy: TradeLargeIntegerPolicy, 34 } 35 36 pub const TRADE_TYPE_INVENTORY: &[TradeTypeInventoryEntry] = &[ 37 event_import("RadrootsFarmRef"), 38 event_import("RadrootsOperationalListing"), 39 event_import("RadrootsOperationalListingAvailability"), 40 event_import("RadrootsOperationalListingBin"), 41 event_import("RadrootsOperationalListingDeliveryMethod"), 42 event_import("RadrootsOperationalListingProduct"), 43 event_import("RadrootsOperationalListingPublicLocation"), 44 event_import("RadrootsOperationalListingStatus"), 45 local_shape("RadrootsTradeFacetCount"), 46 source_root("RadrootsTradeAgreementStateV1"), 47 source_root("RadrootsTradeAttestationStateV1"), 48 source_root("RadrootsTradeConflictStateV1"), 49 source_root("RadrootsTradeEvidenceStateV1"), 50 source_root("RadrootsTradeEvidenceCoverageV1"), 51 source_root("RadrootsTradeEvidenceOutcomeV1"), 52 source_root("RadrootsTradeEvidenceManifestV1"), 53 source_root("RadrootsRhiEvidenceSupersessionV1"), 54 source_root("RadrootsRhiEvidenceReportV1"), 55 source_root("RadrootsRhiEvidenceAttestationV1"), 56 local_shape("RadrootsTypedEvidenceEventPlanV1"), 57 source_root("RadrootsTradeFulfillmentStateV1"), 58 source_root("RadrootsOperationalListingTradeProjection"), 59 local_shape("RadrootsTradeListingBackofficeOverlay"), 60 local_shape("RadrootsTradeListingBackofficeQuery"), 61 local_shape("RadrootsTradeListingBackofficeView"), 62 local_shape("RadrootsTradeListingBinProjection"), 63 local_shape("RadrootsTradeListingFacets"), 64 local_shape("RadrootsTradeListingMarketStatus"), 65 local_shape("RadrootsTradeListingProjection"), 66 local_shape("RadrootsTradeListingQuery"), 67 local_shape("RadrootsTradeListingSort"), 68 local_shape("RadrootsTradeListingSortField"), 69 source_root("RadrootsOperationalListingSubtotal"), 70 source_root("RadrootsOperationalListingTotal"), 71 local_shape("RadrootsTradeMarketplaceListingSummary"), 72 local_shape("RadrootsTradeModerationFlag"), 73 local_shape("RadrootsTradeModerationSeverity"), 74 local_shape("RadrootsTradeModerationStatus"), 75 source_root("RadrootsTradeNegotiationStateV1"), 76 source_root("RadrootsTradePaymentStateV1"), 77 source_root("RadrootsTradePrivateTermsStateV1"), 78 source_root("RadrootsTradeProjectionV1"), 79 local_shape("RadrootsTradeReviewPriority"), 80 local_shape("RadrootsTradeReviewQueueEntry"), 81 local_shape("RadrootsTradeReviewStatus"), 82 local_shape("RadrootsTradeSortDirection"), 83 ]; 84 85 pub const TRADE_LARGE_INTEGER_POLICIES: &[TradeLargeIntegerPolicyEntry] = &[ 86 decimal_string_u64("RadrootsTradeEvidenceManifestV1", "trade_generation"), 87 decimal_string_u64("RadrootsTradeEvidenceManifestV1", "observed_at_unix_s"), 88 decimal_string_u64("RadrootsRhiEvidenceReportV1", "trade_generation"), 89 decimal_string_u64("RadrootsRhiEvidenceReportV1", "observed_at_unix_s"), 90 decimal_string_u64("RadrootsRhiEvidenceAttestationV1", "trade_generation"), 91 decimal_string_u64("RadrootsRhiEvidenceAttestationV1", "observed_at_unix_s"), 92 decimal_string_u64("RadrootsTypedEvidenceEventPlanV1", "created_at_unix_s"), 93 json_number_safe_count("RadrootsTradeFacetCount", "count"), 94 json_number_safe_count( 95 "RadrootsTradeListingBackofficeView", 96 "open_moderation_flag_count", 97 ), 98 json_number_safe_count("RadrootsTradeListingProjection", "trade_count"), 99 json_number_safe_count("RadrootsTradeListingProjection", "open_trade_count"), 100 json_number_safe_count("RadrootsTradeListingProjection", "terminal_trade_count"), 101 json_number_safe_count("RadrootsTradeMarketplaceListingSummary", "trade_count"), 102 json_number_safe_count("RadrootsTradeMarketplaceListingSummary", "open_trade_count"), 103 json_number_safe_count( 104 "RadrootsTradeMarketplaceListingSummary", 105 "terminal_trade_count", 106 ), 107 ]; 108 109 #[cfg_attr(coverage_nightly, coverage(off))] 110 const fn source_root(export_name: &'static str) -> TradeTypeInventoryEntry { 111 TradeTypeInventoryEntry { 112 export_name, 113 disposition: TradeTypeDisposition::SourceTradeRoot, 114 } 115 } 116 117 #[cfg_attr(coverage_nightly, coverage(off))] 118 const fn event_import(export_name: &'static str) -> TradeTypeInventoryEntry { 119 TradeTypeInventoryEntry { 120 export_name, 121 disposition: TradeTypeDisposition::EventsBindingImport, 122 } 123 } 124 125 #[cfg_attr(coverage_nightly, coverage(off))] 126 const fn local_shape(export_name: &'static str) -> TradeTypeInventoryEntry { 127 TradeTypeInventoryEntry { 128 export_name, 129 disposition: TradeTypeDisposition::SdkLocalPackageShape, 130 } 131 } 132 133 #[cfg_attr(coverage_nightly, coverage(off))] 134 const fn json_number_safe_count( 135 type_name: &'static str, 136 field_name: &'static str, 137 ) -> TradeLargeIntegerPolicyEntry { 138 TradeLargeIntegerPolicyEntry { 139 type_name, 140 field_name, 141 policy: TradeLargeIntegerPolicy::JsonNumberSafeCount, 142 } 143 } 144 145 #[cfg_attr(coverage_nightly, coverage(off))] 146 const fn decimal_string_u64( 147 type_name: &'static str, 148 field_name: &'static str, 149 ) -> TradeLargeIntegerPolicyEntry { 150 TradeLargeIntegerPolicyEntry { 151 type_name, 152 field_name, 153 policy: TradeLargeIntegerPolicy::DecimalStringU64, 154 } 155 } 156 157 /// Validates that the checked-in trade binding inventory is internally coherent. 158 #[must_use] 159 pub fn inventory_is_valid() -> bool { 160 inventory_entries_are_valid(TRADE_TYPE_INVENTORY, TRADE_LARGE_INTEGER_POLICIES) 161 } 162 163 fn inventory_entries_are_valid( 164 types: &[TradeTypeInventoryEntry], 165 policies: &[TradeLargeIntegerPolicyEntry], 166 ) -> bool { 167 !types.is_empty() 168 && types.iter().enumerate().all(|(index, entry)| { 169 !entry.export_name.is_empty() 170 && !types[..index] 171 .iter() 172 .any(|prior| prior.export_name == entry.export_name) 173 }) 174 && policies.iter().all(|policy| { 175 !policy.field_name.is_empty() 176 && types 177 .iter() 178 .any(|entry| entry.export_name == policy.type_name) 179 }) 180 } 181 182 #[cfg(test)] 183 mod tests { 184 use super::{ 185 TRADE_LARGE_INTEGER_POLICIES, TRADE_TYPE_INVENTORY, TradeLargeIntegerPolicy, 186 TradeLargeIntegerPolicyEntry, TradeTypeDisposition, TradeTypeInventoryEntry, 187 inventory_entries_are_valid, inventory_is_valid, 188 }; 189 190 #[test] 191 fn checked_in_inventory_is_coherent_and_invalid_shapes_fail_closed() { 192 assert!(inventory_is_valid()); 193 assert!(!inventory_entries_are_valid(&[], &[])); 194 195 let valid = TradeTypeInventoryEntry { 196 export_name: "Valid", 197 disposition: TradeTypeDisposition::SourceTradeRoot, 198 }; 199 let empty = TradeTypeInventoryEntry { 200 export_name: "", 201 disposition: TradeTypeDisposition::SourceTradeRoot, 202 }; 203 assert!(!inventory_entries_are_valid(&[empty], &[])); 204 assert!(!inventory_entries_are_valid(&[valid, valid], &[])); 205 206 let empty_field = TradeLargeIntegerPolicyEntry { 207 type_name: "Valid", 208 field_name: "", 209 policy: TradeLargeIntegerPolicy::JsonNumberSafeCount, 210 }; 211 let unknown_type = TradeLargeIntegerPolicyEntry { 212 type_name: "Missing", 213 field_name: "count", 214 policy: TradeLargeIntegerPolicy::JsonNumberSafeCount, 215 }; 216 assert!(!inventory_entries_are_valid(&[valid], &[empty_field])); 217 assert!(!inventory_entries_are_valid(&[valid], &[unknown_type])); 218 } 219 220 #[test] 221 fn trade_type_inventory_is_deterministic() { 222 let expected = TRADE_TYPE_INVENTORY 223 .iter() 224 .map(|entry| entry.export_name) 225 .collect::<Vec<_>>(); 226 227 assert_eq!( 228 expected, 229 [ 230 "RadrootsFarmRef", 231 "RadrootsOperationalListing", 232 "RadrootsOperationalListingAvailability", 233 "RadrootsOperationalListingBin", 234 "RadrootsOperationalListingDeliveryMethod", 235 "RadrootsOperationalListingProduct", 236 "RadrootsOperationalListingPublicLocation", 237 "RadrootsOperationalListingStatus", 238 "RadrootsTradeFacetCount", 239 "RadrootsTradeAgreementStateV1", 240 "RadrootsTradeAttestationStateV1", 241 "RadrootsTradeConflictStateV1", 242 "RadrootsTradeEvidenceStateV1", 243 "RadrootsTradeEvidenceCoverageV1", 244 "RadrootsTradeEvidenceOutcomeV1", 245 "RadrootsTradeEvidenceManifestV1", 246 "RadrootsRhiEvidenceSupersessionV1", 247 "RadrootsRhiEvidenceReportV1", 248 "RadrootsRhiEvidenceAttestationV1", 249 "RadrootsTypedEvidenceEventPlanV1", 250 "RadrootsTradeFulfillmentStateV1", 251 "RadrootsOperationalListingTradeProjection", 252 "RadrootsTradeListingBackofficeOverlay", 253 "RadrootsTradeListingBackofficeQuery", 254 "RadrootsTradeListingBackofficeView", 255 "RadrootsTradeListingBinProjection", 256 "RadrootsTradeListingFacets", 257 "RadrootsTradeListingMarketStatus", 258 "RadrootsTradeListingProjection", 259 "RadrootsTradeListingQuery", 260 "RadrootsTradeListingSort", 261 "RadrootsTradeListingSortField", 262 "RadrootsOperationalListingSubtotal", 263 "RadrootsOperationalListingTotal", 264 "RadrootsTradeMarketplaceListingSummary", 265 "RadrootsTradeModerationFlag", 266 "RadrootsTradeModerationSeverity", 267 "RadrootsTradeModerationStatus", 268 "RadrootsTradeNegotiationStateV1", 269 "RadrootsTradePaymentStateV1", 270 "RadrootsTradePrivateTermsStateV1", 271 "RadrootsTradeProjectionV1", 272 "RadrootsTradeReviewPriority", 273 "RadrootsTradeReviewQueueEntry", 274 "RadrootsTradeReviewStatus", 275 "RadrootsTradeSortDirection" 276 ] 277 ); 278 } 279 280 #[test] 281 fn source_owned_trade_support_types_are_marked_for_event_import() { 282 for export_name in [ 283 "RadrootsFarmRef", 284 "RadrootsOperationalListing", 285 "RadrootsOperationalListingAvailability", 286 "RadrootsOperationalListingBin", 287 "RadrootsOperationalListingDeliveryMethod", 288 "RadrootsOperationalListingProduct", 289 "RadrootsOperationalListingPublicLocation", 290 "RadrootsOperationalListingStatus", 291 ] { 292 assert_eq!( 293 disposition(export_name), 294 TradeTypeDisposition::EventsBindingImport 295 ); 296 } 297 } 298 299 #[test] 300 fn trade_source_roots_are_marked_for_source_registry() { 301 let source_roots = TRADE_TYPE_INVENTORY 302 .iter() 303 .filter(|entry| entry.disposition == TradeTypeDisposition::SourceTradeRoot) 304 .map(|entry| entry.export_name) 305 .collect::<Vec<_>>(); 306 307 assert_eq!( 308 source_roots, 309 [ 310 "RadrootsTradeAgreementStateV1", 311 "RadrootsTradeAttestationStateV1", 312 "RadrootsTradeConflictStateV1", 313 "RadrootsTradeEvidenceStateV1", 314 "RadrootsTradeEvidenceCoverageV1", 315 "RadrootsTradeEvidenceOutcomeV1", 316 "RadrootsTradeEvidenceManifestV1", 317 "RadrootsRhiEvidenceSupersessionV1", 318 "RadrootsRhiEvidenceReportV1", 319 "RadrootsRhiEvidenceAttestationV1", 320 "RadrootsTradeFulfillmentStateV1", 321 "RadrootsOperationalListingTradeProjection", 322 "RadrootsOperationalListingSubtotal", 323 "RadrootsOperationalListingTotal", 324 "RadrootsTradeNegotiationStateV1", 325 "RadrootsTradePaymentStateV1", 326 "RadrootsTradePrivateTermsStateV1", 327 "RadrootsTradeProjectionV1" 328 ] 329 ); 330 } 331 332 #[test] 333 fn trade_source_support_types_are_marked_for_source_registry() { 334 assert!( 335 TRADE_TYPE_INVENTORY 336 .iter() 337 .all(|entry| entry.disposition != TradeTypeDisposition::SourceTradeSupport) 338 ); 339 } 340 341 #[test] 342 fn trade_large_integer_policy_covers_current_count_fields() { 343 let actual = TRADE_LARGE_INTEGER_POLICIES 344 .iter() 345 .map(|entry| (entry.type_name, entry.field_name, entry.policy)) 346 .collect::<Vec<_>>(); 347 348 assert_eq!( 349 actual, 350 [ 351 ( 352 "RadrootsTradeEvidenceManifestV1", 353 "trade_generation", 354 super::TradeLargeIntegerPolicy::DecimalStringU64 355 ), 356 ( 357 "RadrootsTradeEvidenceManifestV1", 358 "observed_at_unix_s", 359 super::TradeLargeIntegerPolicy::DecimalStringU64 360 ), 361 ( 362 "RadrootsRhiEvidenceReportV1", 363 "trade_generation", 364 super::TradeLargeIntegerPolicy::DecimalStringU64 365 ), 366 ( 367 "RadrootsRhiEvidenceReportV1", 368 "observed_at_unix_s", 369 super::TradeLargeIntegerPolicy::DecimalStringU64 370 ), 371 ( 372 "RadrootsRhiEvidenceAttestationV1", 373 "trade_generation", 374 super::TradeLargeIntegerPolicy::DecimalStringU64 375 ), 376 ( 377 "RadrootsRhiEvidenceAttestationV1", 378 "observed_at_unix_s", 379 super::TradeLargeIntegerPolicy::DecimalStringU64 380 ), 381 ( 382 "RadrootsTypedEvidenceEventPlanV1", 383 "created_at_unix_s", 384 super::TradeLargeIntegerPolicy::DecimalStringU64 385 ), 386 ( 387 "RadrootsTradeFacetCount", 388 "count", 389 super::TradeLargeIntegerPolicy::JsonNumberSafeCount 390 ), 391 ( 392 "RadrootsTradeListingBackofficeView", 393 "open_moderation_flag_count", 394 super::TradeLargeIntegerPolicy::JsonNumberSafeCount 395 ), 396 ( 397 "RadrootsTradeListingProjection", 398 "trade_count", 399 super::TradeLargeIntegerPolicy::JsonNumberSafeCount 400 ), 401 ( 402 "RadrootsTradeListingProjection", 403 "open_trade_count", 404 super::TradeLargeIntegerPolicy::JsonNumberSafeCount 405 ), 406 ( 407 "RadrootsTradeListingProjection", 408 "terminal_trade_count", 409 super::TradeLargeIntegerPolicy::JsonNumberSafeCount 410 ), 411 ( 412 "RadrootsTradeMarketplaceListingSummary", 413 "trade_count", 414 super::TradeLargeIntegerPolicy::JsonNumberSafeCount 415 ), 416 ( 417 "RadrootsTradeMarketplaceListingSummary", 418 "open_trade_count", 419 super::TradeLargeIntegerPolicy::JsonNumberSafeCount 420 ), 421 ( 422 "RadrootsTradeMarketplaceListingSummary", 423 "terminal_trade_count", 424 super::TradeLargeIntegerPolicy::JsonNumberSafeCount 425 ), 426 ] 427 ); 428 } 429 430 fn disposition(export_name: &str) -> TradeTypeDisposition { 431 TRADE_TYPE_INVENTORY 432 .iter() 433 .find(|entry| entry.export_name == export_name) 434 .map(|entry| entry.disposition) 435 .expect("inventory entry") 436 } 437 }