lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

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 }