Skip to main content

triblespace_core/
metadata.rs

1//! Metadata namespace for the `triblespace` crate.
2//!
3//! This namespace is used to bootstrap the meaning of other namespaces.
4//! It defines meta attributes that are used to describe other attributes.
5
6use crate::blob::encodings::longstring::LongString;
7use crate::blob::encodings::wasmcode::WasmCode;
8use crate::id::Id;
9use crate::id_hex;
10use crate::prelude::inlineencodings;
11use crate::trible::Fragment;
12use core::marker::PhantomData;
13use triblespace_core_macros::attributes;
14
15/// Describes a runtime *instance* — emits metadata about a specific value (an
16/// `Attribute<S>` with its id+name+usage, etc.). For describing a Rust *type*
17/// itself (schema metadata for `ShortString`, `Handle<T>`, …) use
18/// [`MetaDescribe`].
19///
20/// `describe` returns a [`Fragment`] that's self-contained — its
21/// embedded [`crate::blob::MemoryBlobStore`] holds any bytes the
22/// returned facts reference by handle. Consumers wanting to persist
23/// the description hand the fragment to a workspace.
24pub trait Describe {
25    /// Produces a [`Fragment`] describing this instance, with any
26    /// long-form bytes embedded in its local blob store.
27    fn describe(&self) -> Fragment;
28
29    /// Returns the id of this instance. Default: derive from
30    /// `self.describe().root()`. Override when the id is cheaper to
31    /// compute directly (e.g. `Attribute<S>` reads it from its
32    /// stored fragment).
33    fn id(&self) -> Id {
34        self.describe()
35            .root()
36            .expect("describe returns a rooted fragment")
37    }
38}
39
40/// Describes a Rust *type* — emits schema metadata about the type itself
41/// without needing an instance (`ShortString`, `Handle<T>`, …). For
42/// describing a runtime value use [`Describe`].
43///
44/// Same self-contained Fragment contract as [`Describe`]: the
45/// returned Fragment's local blob store holds the bytes for any
46/// handles in its facts.
47pub trait MetaDescribe {
48    /// Produces a [`Fragment`] describing this schema type.
49    fn describe() -> Fragment;
50
51    /// Returns the id of this type. Default: derive from
52    /// `Self::describe().root()`. Impls choose whether the id is
53    /// *explicit* (an `entity!{ &id_hex @ … }` form inside describe)
54    /// or *derived* (no `@`, intrinsic id from the facts) — either
55    /// way the default reads the root the fragment carries.
56    ///
57    /// Impls **must not** call `Self::id()` from inside their `describe`
58    /// body — that would recurse through this default. Use the literal id
59    /// directly in describe() or rely on no-`@` intrinsic derivation.
60    ///
61    /// No caching: each call re-runs describe + root. If id() becomes a hot
62    /// path, layer a `TypeId`-keyed cache on top from the call site.
63    fn id() -> Id {
64        <Self as MetaDescribe>::describe()
65            .root()
66            .expect("describe returns a rooted fragment")
67    }
68}
69
70impl<S> Describe for PhantomData<S>
71where
72    S: MetaDescribe,
73{
74    fn describe(&self) -> Fragment {
75        <S as MetaDescribe>::describe()
76    }
77
78    // id() uses the default (describe + root).
79}
80
81// namespace constants
82/// Tag for entities that can have multiple simultaneous kinds.
83pub const KIND_MULTI: Id = id_hex!("C36D9C16B34729D855BD6C36A624E1BF");
84/// Tag for entities that represent inline encodings.
85pub const KIND_INLINE_ENCODING: Id = id_hex!("9A169BF2383E7B1A3E019808DFE3C2EB");
86/// Tag for entities that represent blob encodings.
87pub const KIND_BLOB_ENCODING: Id = id_hex!("CE488DB0C494C7FDBF3DF1731AED68A6");
88/// Tag for entities that describe an attribute usage in some source context.
89pub const KIND_ATTRIBUTE_USAGE: Id = id_hex!("45759727A79C28D657EC06D5C6013649");
90/// Tag for entities that describe a protocol.
91pub const KIND_PROTOCOL: Id = id_hex!("A04AD649FA28DC5904385532E9C8EF74");
92/// Tag for entities that are themselves tag/marker constants (e.g. kind discriminants).
93pub const KIND_TAG: Id = id_hex!("452584B4C1CAE0B77F44408E6F194A31");
94
95attributes! {
96    /// Optional long-form description stored as a LongString handle.
97    ///
98    /// This attribute is general-purpose: it can describe any entity. Schema
99    /// metadata uses it for documenting value/blob encodings, but it is equally
100    /// valid for domain entities.
101    "AE94660A55D2EE3C428D2BB299E02EC3" as description: inlineencodings::Handle<LongString>;
102    /// Links an attribute or handle to its inline encoding identifier.
103    "213F89E3F49628A105B3830BD3A6612C" as value_encoding: inlineencodings::GenId;
104    /// Links a handle to its blob encoding identifier.
105    "43C134652906547383054B1E31E23DF4" as blob_encoding: inlineencodings::GenId;
106    /// Links an `Array<T>` schema entity to its element schema's id. Distinct
107    /// from `blob_encoding` because element schemas are not themselves
108    /// `BlobEncoding`s — they only carry an `ArrayElement::Native` byte-layout.
109    "56C43BEE48BE99521886D99BE9026A3B" as array_item_schema: inlineencodings::GenId;
110    /// Links a handle to the hash algorithm used for content addressing.
111    "51C08CFABB2C848CE0B4A799F0EFE5EA" as hash_schema: inlineencodings::GenId;
112    /// Optional WebAssembly module for formatting values governed by this schema.
113    ///
114    /// The value is a `Handle<WasmCode>` that points to a sandboxed
115    /// formatter module (see `triblespace_core::value_formatter`).
116    "1A3D520FEDA9E1A4051EBE96E43ABAC7" as value_formatter: inlineencodings::Handle<WasmCode>;
117    /// Long-form display name stored as a LongString handle.
118    ///
119    /// Names are *display*-oriented and contextual: multiple usages of the
120    /// same attribute may carry different names depending on the codebase
121    /// or domain. Use attribute usage entities (tagged with
122    /// `KIND_ATTRIBUTE_USAGE`) when you need to capture multiple names for
123    /// the same attribute id.
124    ///
125    /// For *identity*-determining strings (an IRI for RDF, an export
126    /// symbol for WASM, …), use a dedicated attribute like
127    /// [`iri`](`self::iri`) instead. The id-derivation paths for dynamic
128    /// attributes hash from those identity-determining attributes, not
129    /// from `name`.
130    "7FB28C0B48E1924687857310EE230414" as name: inlineencodings::Handle<LongString>;
131    /// Internationalized Resource Identifier (IRI) for this entity.
132    ///
133    /// The canonical identity-determining string for RDF predicate URIs and
134    /// RDF entity URIs. Distinct from [`name`] (display) so an IRI-derived
135    /// attribute and a same-bytes JSON-field-derived attribute never
136    /// collide: the (attr_id, value) pair that participates in
137    /// entity-intrinsic-id derivation differs in the attr_id, even when the
138    /// raw value bytes are identical.
139    ///
140    /// The value is stored as a `Handle<LongString>` — IRI-ness is a
141    /// semantic property of *this attribute*, not a structural property of
142    /// the bytes. Callers that need IRI-shape validation can apply
143    /// it at the application boundary; the storage layer doesn't enforce
144    /// it, so mistyped or placeholder IRIs ingest without rejection and
145    /// queries can unify across "any string this entity has."
146    "325F05DB88184B4540AAEEFAE1E9667F" as iri: inlineencodings::Handle<LongString>;
147    /// Link a usage annotation entity to the attribute it describes.
148    "F10DE6D8E60E0E86013F1B867173A85C" as attribute: inlineencodings::GenId;
149    /// Optional provenance string for a usage annotation.
150    "A56350FD00EC220B4567FE15A5CD68B8" as source: inlineencodings::Handle<LongString>;
151    /// Optional module path for the usage annotation (from `module_path!()`).
152    "BCB94C7439215641A3E9760CE3F4F432" as source_module: inlineencodings::Handle<LongString>;
153    /// Preferred JSON representation (e.g. string, number, bool, object, ref, blob).
154    /// Preferred JSON representation hint (e.g. `"string"`, `"number"`, `"bool"`, `"object"`).
155    "A7AFC8C0FAD017CE7EC19587AF682CFF" as json_kind: inlineencodings::ShortString;
156    /// Generic tag edge: link any entity to a tag entity (by Id). Reusable across domains.
157    "91C50E9FBB1F73E892EBD5FFDE46C251" as tag: inlineencodings::GenId;
158    /// When an entity was created.
159    "9B1E79DFD065F643954141593CD8B9E0" as created_at: inlineencodings::NsTAIInterval;
160    /// When an entity was last updated.
161    "93B7372E3443063392CD801B03A8D390" as updated_at: inlineencodings::NsTAIInterval;
162    /// When a process or interval started.
163    "06973030ACA83A7B2B4FC8BEBB31F77A" as started_at: inlineencodings::NsTAIInterval;
164    /// When a process or interval finished.
165    "9B06AA4060EF9928A923FC7E6A6B6438" as finished_at: inlineencodings::NsTAIInterval;
166    /// When an entity expires or becomes invalid.
167    "89FEC3B560336BA88B10759DECD3155F" as expires_at: inlineencodings::NsTAIInterval;
168}