lib

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

commit a06255f2a44c5161b3abf4289c91668fd7e2fea4
parent ec0c52e71c120f75bfe581fb847b611ceb48978b
Author: triesap <tyson@radroots.org>
Date:   Wed, 24 Jun 2026 07:53:07 +0000

dto: describe indexed event bindings

- Add an optional dto-bindgen feature for radroots_events_indexed.

- Derive source DTO descriptors for manifest and ID range shapes.

- Add manual checkpoint descriptors for custom epoch-second wire fields.

- Cover indexed registry construction and timestamp field policy with tests.

Diffstat:
MCargo.lock | 2++
Mcrates/events_indexed/Cargo.toml | 3+++
Acrates/events_indexed/src/dto.rs | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/events_indexed/src/lib.rs | 2++
Mcrates/events_indexed/src/manifest.rs | 2++
Mcrates/events_indexed/src/types.rs | 1+
6 files changed, 172 insertions(+), 0 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -4323,6 +4323,8 @@ dependencies = [ name = "radroots_events_indexed" version = "0.1.0-alpha.2" dependencies = [ + "dto_bindgen", + "dto_bindgen_core", "serde", "serde_json", ] diff --git a/crates/events_indexed/Cargo.toml b/crates/events_indexed/Cargo.toml @@ -14,10 +14,13 @@ readme = "README" [features] default = ["serde"] +dto-bindgen = ["std", "serde", "dep:dto_bindgen", "dep:dto_bindgen_core"] serde = ["dep:serde"] std = [] [dependencies] +dto_bindgen = { workspace = true, optional = true } +dto_bindgen_core = { workspace = true, optional = true } serde = { workspace = true, default-features = false, features = [ "alloc", "derive", diff --git a/crates/events_indexed/src/dto.rs b/crates/events_indexed/src/dto.rs @@ -0,0 +1,162 @@ +use dto_bindgen_core::{ + BackendId, DescribeCtx, Dto, FieldDef, IdentName, RootDescriptor, RustTypeId, SourceSpan, + StructDef, TargetFieldNames, TargetOverride, TypeDef, TypeRef, WireFieldNames, +}; + +use crate::{ + checkpoint::{RadrootsEventsIndexedIndexCheckpoint, RadrootsEventsIndexedShardCheckpoint}, + manifest::{RadrootsEventsIndexedManifest, RadrootsEventsIndexedShardMetadata}, + types::RadrootsEventsIndexedIdRange, +}; + +pub fn dto_roots() -> [RootDescriptor; 5] { + [ + RootDescriptor::new::<RadrootsEventsIndexedIdRange>(), + RootDescriptor::new::<RadrootsEventsIndexedShardMetadata>(), + RootDescriptor::new::<RadrootsEventsIndexedManifest>(), + RootDescriptor::new::<RadrootsEventsIndexedShardCheckpoint>(), + RootDescriptor::new::<RadrootsEventsIndexedIndexCheckpoint>(), + ] +} + +impl Dto for RadrootsEventsIndexedShardCheckpoint { + fn describe(ctx: &mut DescribeCtx) -> TypeRef { + let def = StructDef::new( + "RadrootsEventsIndexedShardCheckpoint", + "RadrootsEventsIndexedShardCheckpoint", + span("crates/events_indexed/src/checkpoint.rs", 10), + ) + .with_field(field( + "shard_id", + "shard_id", + shard_id_ref(), + "crates/events_indexed/src/checkpoint.rs", + 11, + )) + .with_field(field( + "last_created_at", + "last_created_at", + u32::describe(ctx), + "crates/events_indexed/src/checkpoint.rs", + 16, + )) + .with_field(field( + "last_event_id", + "last_event_id", + <Option<String> as Dto>::describe(ctx), + "crates/events_indexed/src/checkpoint.rs", + 17, + )) + .with_field(field( + "cursor", + "cursor", + <Option<String> as Dto>::describe(ctx), + "crates/events_indexed/src/checkpoint.rs", + 18, + )); + register( + ctx, + "RadrootsEventsIndexedShardCheckpoint", + TypeDef::Struct(def), + ) + } +} + +impl Dto for RadrootsEventsIndexedIndexCheckpoint { + fn describe(ctx: &mut DescribeCtx) -> TypeRef { + let def = StructDef::new( + "RadrootsEventsIndexedIndexCheckpoint", + "RadrootsEventsIndexedIndexCheckpoint", + span("crates/events_indexed/src/checkpoint.rs", 24), + ) + .with_field(field( + "generated_at", + "generated_at", + u32::describe(ctx), + "crates/events_indexed/src/checkpoint.rs", + 30, + )) + .with_field(field( + "shards", + "shards", + <Vec<RadrootsEventsIndexedShardCheckpoint> as Dto>::describe(ctx), + "crates/events_indexed/src/checkpoint.rs", + 31, + )); + register( + ctx, + "RadrootsEventsIndexedIndexCheckpoint", + TypeDef::Struct(def), + ) + } +} + +fn register(ctx: &mut DescribeCtx, rust_ident: &str, type_def: TypeDef) -> TypeRef { + ctx.register_type( + RustTypeId::new("radroots_events_indexed", rust_ident), + type_def, + ) +} + +fn shard_id_ref() -> TypeRef { + TypeRef::Override(TargetOverride::new( + BackendId::TypeScript, + "RadrootsEventsIndexedShardId", + )) +} + +fn field(rust_name: &str, wire_name: &str, ty: TypeRef, file: &str, line: u32) -> FieldDef { + FieldDef::new( + IdentName::new(rust_name), + WireFieldNames::same(wire_name), + TargetFieldNames::new(wire_name, rust_name), + ty, + span(file, line), + ) +} + +fn span(file: &str, line: u32) -> SourceSpan { + SourceSpan::new(file, line, 1) +} + +#[cfg(test)] +mod tests { + use dto_bindgen_core::{Primitive, TypeDef, TypeRef, build_registry}; + + use super::dto_roots; + + #[test] + fn indexed_descriptor_roots_build_registry() { + let registry = build_registry(dto_roots()); + + assert!(!registry.has_errors()); + assert_eq!(registry.roots.len(), dto_roots().len()); + assert!(registry.types_by_id.values().any( + |def| matches!(def, TypeDef::Struct(def) if def.export_name == "RadrootsEventsIndexedManifest") + )); + } + + #[test] + fn custom_epoch_second_fields_render_as_numbers() { + let registry = build_registry(dto_roots()); + let checkpoint = registry + .types_by_id + .values() + .find_map(|def| match def { + TypeDef::Struct(def) + if def.export_name == "RadrootsEventsIndexedShardCheckpoint" => + { + Some(def) + } + _ => None, + }) + .expect("checkpoint descriptor"); + let field = checkpoint + .fields + .iter() + .find(|field| field.target.typescript == "last_created_at") + .expect("last_created_at field"); + + assert_eq!(field.ty, TypeRef::Primitive(Primitive::U32)); + } +} diff --git a/crates/events_indexed/src/lib.rs b/crates/events_indexed/src/lib.rs @@ -3,6 +3,8 @@ extern crate alloc; pub mod checkpoint; +#[cfg(feature = "dto-bindgen")] +pub mod dto; pub mod manifest; pub mod serde_ext; pub mod types; diff --git a/crates/events_indexed/src/manifest.rs b/crates/events_indexed/src/manifest.rs @@ -3,6 +3,7 @@ use alloc::{string::String, vec::Vec}; use core::fmt; +#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Debug, PartialEq, Eq)] pub struct RadrootsEventsIndexedShardMetadata { @@ -15,6 +16,7 @@ pub struct RadrootsEventsIndexedShardMetadata { pub sha256: String, } +#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Debug, PartialEq, Eq)] pub struct RadrootsEventsIndexedManifest { diff --git a/crates/events_indexed/src/types.rs b/crates/events_indexed/src/types.rs @@ -5,6 +5,7 @@ use alloc::string::String; #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct RadrootsEventsIndexedShardId(pub String); +#[cfg_attr(feature = "dto-bindgen", derive(dto_bindgen::Dto))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Debug, PartialEq, Eq)] pub struct RadrootsEventsIndexedIdRange {