lib

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

dto.rs (9120B)


      1 use dto_bindgen_core::{
      2     BackendId, DescribeCtx, Dto, FieldDef, IdentName, RootDescriptor, RustTypeId, SourceSpan,
      3     StructDef, TargetFieldNames, TargetOverride, TypeDef, TypeRef, WireFieldNames,
      4 };
      5 
      6 use crate::listing::{
      7     model::{RadrootsTradeListingSubtotal, RadrootsTradeListingTotal},
      8     validation::RadrootsTradeListing,
      9 };
     10 
     11 pub fn dto_roots() -> [RootDescriptor; 3] {
     12     [
     13         RootDescriptor::new::<RadrootsTradeListing>(),
     14         RootDescriptor::new::<RadrootsTradeListingSubtotal>(),
     15         RootDescriptor::new::<RadrootsTradeListingTotal>(),
     16     ]
     17 }
     18 
     19 impl Dto for RadrootsTradeListing {
     20     fn describe(ctx: &mut DescribeCtx) -> TypeRef {
     21         let def = StructDef::new(
     22             "RadrootsTradeListing",
     23             "RadrootsTradeListing",
     24             span("crates/trade/src/listing/validation.rs", 25),
     25         )
     26         .with_field(field(
     27             "listing_id",
     28             "listing_id",
     29             String::describe(ctx),
     30             "crates/trade/src/listing/validation.rs",
     31             26,
     32         ))
     33         .with_field(field(
     34             "listing_addr",
     35             "listing_addr",
     36             String::describe(ctx),
     37             "crates/trade/src/listing/validation.rs",
     38             27,
     39         ))
     40         .with_field(field(
     41             "seller_pubkey",
     42             "seller_pubkey",
     43             String::describe(ctx),
     44             "crates/trade/src/listing/validation.rs",
     45             28,
     46         ))
     47         .with_field(field(
     48             "title",
     49             "title",
     50             String::describe(ctx),
     51             "crates/trade/src/listing/validation.rs",
     52             29,
     53         ))
     54         .with_field(field(
     55             "description",
     56             "description",
     57             String::describe(ctx),
     58             "crates/trade/src/listing/validation.rs",
     59             30,
     60         ))
     61         .with_field(field(
     62             "product_type",
     63             "product_type",
     64             String::describe(ctx),
     65             "crates/trade/src/listing/validation.rs",
     66             31,
     67         ))
     68         .with_field(field(
     69             "primary_bin_id",
     70             "primary_bin_id",
     71             String::describe(ctx),
     72             "crates/trade/src/listing/validation.rs",
     73             32,
     74         ))
     75         .with_field(field(
     76             "bin_quantity",
     77             "bin_quantity",
     78             ts_ref("RadrootsCoreQuantity"),
     79             "crates/trade/src/listing/validation.rs",
     80             33,
     81         ))
     82         .with_field(field(
     83             "unit",
     84             "unit",
     85             ts_ref("RadrootsCoreUnit"),
     86             "crates/trade/src/listing/validation.rs",
     87             34,
     88         ))
     89         .with_field(field(
     90             "unit_price",
     91             "unit_price",
     92             ts_ref("RadrootsCoreMoney"),
     93             "crates/trade/src/listing/validation.rs",
     94             35,
     95         ))
     96         .with_field(field(
     97             "inventory_available",
     98             "inventory_available",
     99             ts_ref("RadrootsCoreDecimal"),
    100             "crates/trade/src/listing/validation.rs",
    101             36,
    102         ))
    103         .with_field(field(
    104             "availability",
    105             "availability",
    106             ts_ref("RadrootsListingAvailability"),
    107             "crates/trade/src/listing/validation.rs",
    108             37,
    109         ))
    110         .with_field(field(
    111             "location",
    112             "location",
    113             ts_ref("RadrootsListingLocation"),
    114             "crates/trade/src/listing/validation.rs",
    115             38,
    116         ))
    117         .with_field(field(
    118             "delivery_method",
    119             "delivery_method",
    120             ts_ref("RadrootsListingDeliveryMethod"),
    121             "crates/trade/src/listing/validation.rs",
    122             39,
    123         ))
    124         .with_field(field(
    125             "listing",
    126             "listing",
    127             ts_ref("RadrootsListing"),
    128             "crates/trade/src/listing/validation.rs",
    129             40,
    130         ));
    131         register(ctx, "RadrootsTradeListing", TypeDef::Struct(def))
    132     }
    133 }
    134 
    135 impl Dto for RadrootsTradeListingSubtotal {
    136     fn describe(ctx: &mut DescribeCtx) -> TypeRef {
    137         trade_listing_total_like(
    138             ctx,
    139             "RadrootsTradeListingSubtotal",
    140             "crates/trade/src/listing/model.rs",
    141             3,
    142         )
    143     }
    144 }
    145 
    146 impl Dto for RadrootsTradeListingTotal {
    147     fn describe(ctx: &mut DescribeCtx) -> TypeRef {
    148         trade_listing_total_like(
    149             ctx,
    150             "RadrootsTradeListingTotal",
    151             "crates/trade/src/listing/model.rs",
    152             12,
    153         )
    154     }
    155 }
    156 
    157 fn trade_listing_total_like(
    158     ctx: &mut DescribeCtx,
    159     rust_ident: &str,
    160     file: &str,
    161     line: u32,
    162 ) -> TypeRef {
    163     let def = StructDef::new(rust_ident, rust_ident, span(file, line))
    164         .with_field(field(
    165             "price_amount",
    166             "price_amount",
    167             ts_ref("RadrootsCoreMoney"),
    168             file,
    169             line + 1,
    170         ))
    171         .with_field(field(
    172             "price_currency",
    173             "price_currency",
    174             ts_ref("RadrootsCoreCurrency"),
    175             file,
    176             line + 2,
    177         ))
    178         .with_field(field(
    179             "quantity_amount",
    180             "quantity_amount",
    181             ts_ref("RadrootsCoreDecimal"),
    182             file,
    183             line + 3,
    184         ))
    185         .with_field(field(
    186             "quantity_unit",
    187             "quantity_unit",
    188             ts_ref("RadrootsCoreUnit"),
    189             file,
    190             line + 4,
    191         ));
    192     register(ctx, rust_ident, TypeDef::Struct(def))
    193 }
    194 
    195 fn register(ctx: &mut DescribeCtx, rust_ident: &str, type_def: TypeDef) -> TypeRef {
    196     ctx.register_type(RustTypeId::new("radroots_trade", rust_ident), type_def)
    197 }
    198 
    199 fn ts_ref(target_type: &str) -> TypeRef {
    200     TypeRef::Override(TargetOverride::new(BackendId::TypeScript, target_type))
    201 }
    202 
    203 fn field(rust_name: &str, wire_name: &str, ty: TypeRef, file: &str, line: u32) -> FieldDef {
    204     FieldDef::new(
    205         IdentName::new(rust_name),
    206         WireFieldNames::same(wire_name),
    207         TargetFieldNames::new(wire_name, rust_name),
    208         ty,
    209         span(file, line),
    210     )
    211 }
    212 
    213 fn span(file: &str, line: u32) -> SourceSpan {
    214     SourceSpan::new(file, line, 1)
    215 }
    216 
    217 #[cfg(test)]
    218 mod tests {
    219     use dto_bindgen_core::{BackendId, Registry, StructDef, TypeDef, TypeRef, build_registry};
    220 
    221     use super::dto_roots;
    222 
    223     const TRADE_SOURCE_ROOTS: &[&str] = &[
    224         "RadrootsTradeListing",
    225         "RadrootsTradeListingSubtotal",
    226         "RadrootsTradeListingTotal",
    227     ];
    228 
    229     #[test]
    230     fn trade_descriptor_roots_build_registry() {
    231         let registry = build_registry(dto_roots());
    232 
    233         assert!(
    234             !registry.has_errors(),
    235             "trade registry has diagnostics: {:?}",
    236             registry.diagnostics
    237         );
    238         assert_eq!(registry.roots.len(), dto_roots().len());
    239     }
    240 
    241     #[test]
    242     fn trade_source_roots_are_deterministic() {
    243         let registry = build_registry(dto_roots());
    244 
    245         assert_eq!(root_export_names(&registry), TRADE_SOURCE_ROOTS);
    246     }
    247 
    248     #[test]
    249     fn trade_source_fields_use_package_aliases_for_import_boundaries() {
    250         let registry = build_registry(dto_roots());
    251         let listing = find_struct(&registry, "RadrootsTradeListing");
    252         let subtotal = find_struct(&registry, "RadrootsTradeListingSubtotal");
    253 
    254         assert_eq!(
    255             typescript_override_target(field_ty(listing, "inventory_available")),
    256             Some("RadrootsCoreDecimal")
    257         );
    258         assert_eq!(
    259             typescript_override_target(field_ty(listing, "listing")),
    260             Some("RadrootsListing")
    261         );
    262         assert_eq!(
    263             typescript_override_target(field_ty(subtotal, "price_currency")),
    264             Some("RadrootsCoreCurrency")
    265         );
    266     }
    267 
    268     fn root_export_names(registry: &Registry) -> Vec<&str> {
    269         registry
    270             .roots
    271             .iter()
    272             .map(|type_id| {
    273                 registry
    274                     .type_def(*type_id)
    275                     .map(type_export_name)
    276                     .expect("root type")
    277             })
    278             .collect()
    279     }
    280 
    281     fn type_export_name(def: &TypeDef) -> &str {
    282         match def {
    283             TypeDef::Struct(def) => def.export_name.as_str(),
    284             TypeDef::Enum(def) => def.export_name.as_str(),
    285         }
    286     }
    287 
    288     fn find_struct<'a>(registry: &'a Registry, export_name: &str) -> &'a StructDef {
    289         registry
    290             .types_by_id
    291             .values()
    292             .find_map(|def| match def {
    293                 TypeDef::Struct(def) if def.export_name == export_name => Some(def),
    294                 _ => None,
    295             })
    296             .expect("descriptor struct")
    297     }
    298 
    299     fn field_ty<'a>(def: &'a StructDef, field_name: &str) -> &'a TypeRef {
    300         &def.fields
    301             .iter()
    302             .find(|field| field.target.typescript == field_name)
    303             .expect("descriptor field")
    304             .ty
    305     }
    306 
    307     fn typescript_override_target(ty: &TypeRef) -> Option<&str> {
    308         match ty {
    309             TypeRef::Override(target) if target.backend == BackendId::TypeScript => {
    310                 Some(target.target_type.as_str())
    311             }
    312             _ => None,
    313         }
    314     }
    315 }