Skip to main content

Expandable

Derive Macro Expandable 

Source
#[derive(Expandable)]
{
    // Attributes available to this derive:
    #[jsonld]
}
Expand description

Derive Expandable to generate an expand::<V>() impl producing expanded JSON-LD for any V: JsonValue backend.

ⓘ
// The derive macro, plus the trait it implements: `expand()` is a trait
// method, so both names must be in scope. Deriving through the umbrella
// `jsonld` crate, a single `use jsonld::Expandable;` brings both.
use jsonld_expandable::Expandable;
use jsonld_expandable_core::Expandable as _;

#[derive(Expandable)]
#[jsonld(type = "https://example.com/Parent")]
pub struct Parent {
    #[jsonld(id)]
    pub id: String,

    #[jsonld(property = "https://example.com/name")]
    pub name: String,
}

let expanded: serde_json::Value = parent.expand();

§Container attributes

Set on the struct itself, inside #[jsonld(...)]:

AttributeMeaning
type = "IRI-or-CURIE"Static @type for every expanded node.
fragmentEmit the object without @type (a sub-fragment of a parent node). Mutually exclusive with type and a type_value field.
prefix(name = "IRI", ...)Declare CURIE prefixes used by type, property, and coerce values. Hyphenated names work bare (prefix(ngsi-ld = "...")) or quoted (prefix("ngsi-ld" = "...")).
debugReport the generated code as a compile error (for inspection).

Exactly one of type = "...", a type_value field, or fragment is required.

Each struct carries its own prefix table, and the derive sees one struct at a time: a nested or fragment struct needs its own prefix(...) even when its parent declares the same names. A prefix that is not declared is not an error, because ex:name is also a syntactically valid IRI with scheme ex, so it is emitted as written.

The generated code reaches its runtime support through jsonld-expandable-core or through the umbrella jsonld crate’s re-export of it, whichever the consuming crate depends on, following a renamed dependency to the name it was given.

§Field attributes

AttributeMeaning
idField is the node’s @id. String-like (AsRef<str>) or Option thereof; None omits the @id entry.
type_valueField supplies a dynamic @type array via the ExpandableTypeValue trait. At most one per struct; conflicts with container type/fragment.
property = "IRI-or-CURIE"Property IRI the field expands under. Required unless the field is id, skip, flatten, or flatten_map.
skipExclude the field from expansion.
coerce = "@id" / "@vocab"Value is an IRI reference: emits [{"@id": v}] (or @vocab). With vec, iterates the field.
coerce = "@json"JSON literal: emits [{"@value": v, "@type": "@json"}].
coerce = "IRI-or-CURIE"Typed literal: emits [{"@value": v, "@type": "<datatype>"}]. CURIEs expand through this struct’s own prefix(...) table.
container = "list"Wrap values as [{"@list": [...]}]. Composes with coerce and nested for per-item shapes.
container = "set"Emit the value’s ToJsonValue form verbatim (JSON array).
container = "language"Language map: HashMap/BTreeMap of tag to text work as they are, other shapes implement ExpandableLanguageMap.
container = "index"Index map: emits [{"@index": k, "@value": v}, ...] from an iterable of pairs.
nestedField is itself Expandable; recurse. With vec, expands each element.
vecField is a Vec-like iterable; combine with nested or an @id/@vocab coercion.
flattenMerge the expanded properties of a nested Expandable into this node (drops its @id/@type).
flatten_mapMerge a map field: each key becomes a property IRI, each value is expanded recursively.
passthroughThe field’s own Expandable impl produces the final JSON-LD form; emitted verbatim.

Option<T> fields omit their entry when None.

§Limitations

Generic structs are not supported: the derive cannot yet add the T: ToJsonValue<V>-style bounds the generated impl would need. Reserved attributes nest, reverse, and container = "id"/"type"/"graph" fail with an explicit error.