Documentation / Core contracts

Fields & codecs

Describe Resource values.

ROM 0.1.0 · SOURCE CANDIDATE Markdown

A declaration uses the same Field contract for metadata, input decoding, persistence normalization and typed selectors. Supported built-ins are String, bool, u64, i64, FiniteF64, Option<T>, Presence<T>, Vec<T>, BTreeMap<String, T> and ResourceRef<R>. A native plugin implements Field for its own newtype and declares its wire shape. Shape::Enum constrains custom string codecs to a nonempty, distinct list of at most 256 variants.

rust
use rom::{FiniteF64, Resource, ResourceRef};
#[derive(Clone, Resource)]
#[resource(name = "projects")]
struct Project { title: String }
#[derive(Clone, Resource)]
#[resource(name = "measurements")]
struct Measurement {
    project: ResourceRef<Project>,
    reading: FiniteF64,
    labels: Vec<Option<String>>,
}
let reading = FiniteF64::new(0.25)?;
let project = ResourceRef::<Project>::new("project-one")?;
# Ok::<(), rom::Error>(())

Use FiniteF64::new(value) or TryFrom<f64> for floating values. An early trial with raw f64 reproduced a concrete data-loss case: Some(NaN) encoded as JSON null and decoded as None. The maintained wrapper stores a private value. Before construction, it rejects NaN/infinity. It is ordinary binary floating point, not a financial decimal type; decimal/date/UUID fields can be explicit custom codecs without changing the resource runtime.

A ResourceRef<R> carries a nonempty target identity and advertises R's kind. Registration requires that target kind to be registered. Mutual references are allowed. Native commits enforce target existence and restrict deletion, including references inside collections. Unlink a live source before deleting its target. There is no implicit cascade. See reference integrity for replay, registration and maintenance behavior.

Collections validate each element/value. Empty collections, empty strings, false and zero are values. Option<T> uses JSON null. Registration rejects nested nullable shapes such as Vec<Option<Option<bool>>> because that wire form cannot distinguish their states. Shape nesting is limited to 16. These are structural constraints, not a memory allocator budget; the execution boundary also limits serialized commands and snapshots.

Create and replace must include every field except top-level Presence<T> fields. An Option<T> field must still have an explicit value or null. Unknown fields and mismatched shapes are rejected. Partial changes use Command::patch with Patch::set and Patch::remove. Omitted patch entries stay unchanged. Nullable values can be set to null. Only Presence fields can be removed. The same codecs, authorization and revision checks apply. No separate Serde attribute schema is accepted by derive.

Validation evidence: eight public consumer tests exercise roundtrip through the runtime, bad nested data, enum/codecs disagreement, invalid nullable shapes, missing reference kinds, cyclic declarations and nonfinite construction. The complete existing verifier passed after the codec changes; the final two added cases were also independently run with Clippy. The negative NaN experiment failed before replacing the raw-float encoding with FiniteF64.

This page follows the captured repository source.View the source