Dextrin.Struct (Dextrin v0.2.0)

Copy Markdown View Source

Opaque DXN struct value, produced when no schema is compiled for its name (DXN.md §1.4: "a reader lacking the schema... returns an opaque tagged value rather than failing").

fields is one of two shapes, and deliberately not normalized to a single common one — .dxn's keyed literal form carries field names; .dxnb's wire form is always positional (DXN.md §2.1) and never carries names at all. Without a schema there is no way to recover one shape from the other (a positional .dxnb struct has no names to reconstruct), so Dextrin.Struct says which shape it actually is rather than pretend they're interchangeable. This is also why an opaque struct decoded from .dxnb can't be cross-checked against the same struct decoded from .dxn without a schema in hand — there's nothing to compare field-by-field yet.

version is the schema version the struct was written with (%Name(3){...}, DXN.md §4.8), or nil when it was written without one, which a reader takes as the latest version it has loaded.

extra holds the fields a struct carries beyond its declared ones (DXN.md §4.7), as {key, value} pairs in the order they were written: a name for a named field, any other map key (§1.6) as itself. In text they are entries after the fields or the items; in .dxnb, one trailing tag-215 map. Code relying on a struct is guaranteed only its declared fields.

Summary

Functions

An entry's key as an extra field's key: a keyword, symbol or string is a name (its text); any other map key (DXN.md §1.6) is kept as itself.

How a struct literal opens: %Name, or %Name(3) when it carries a version. Shared by every writer, so the printer, the formatter and the canonical form agree.

A struct written with names, at version when one is given, carrying extra.

The other direction: a .dxnb type name read back into its name and version. A version that is not a positive integer is :error.

A struct written by position, at version when one is given, carrying extra.

The extra fields an application struct carries at run time: the keys of value its module's own defstruct does not declare, as named extras. An Elixir struct is a map, so a key put on it after the fact is the struct carrying more than it declares (DXN.md §4.7).

The struct's name as .dxnb writes it: Name, or Name(3) when it carries a version (DXN.md §2.4, §4.8).

Types

fields()

@type fields() :: {:keyed, [{String.t(), term()}]} | {:positional, [term()]}

t()

@type t() :: %Dextrin.Struct{
  extra: [{term(), term()}],
  fields: fields(),
  name: String.t(),
  version: pos_integer() | nil
}

Functions

extra_key(key)

@spec extra_key(term()) :: term()

An entry's key as an extra field's key: a keyword, symbol or string is a name (its text); any other map key (DXN.md §1.6) is kept as itself.

Dextrin.Struct.extra_key(%Dextrin.Keyword{name: "nick"})   #=> "nick"
Dextrin.Struct.extra_key(3)                                #=> 3

head(name, version)

@spec head(String.t(), pos_integer() | nil) :: String.t()

How a struct literal opens: %Name, or %Name(3) when it carries a version. Shared by every writer, so the printer, the formatter and the canonical form agree.

Dextrin.Struct.head("P", 3)   #=> "%P(3)"

keyed(name, pairs, version \\ nil, extra \\ [])

@spec keyed(String.t(), [{String.t(), term()}], pos_integer() | nil, [
  {term(), term()}
]) :: t()

A struct written with names, at version when one is given, carrying extra.

parse_type_name(text)

@spec parse_type_name(String.t()) :: {:ok, String.t(), pos_integer() | nil} | :error

The other direction: a .dxnb type name read back into its name and version. A version that is not a positive integer is :error.

Dextrin.Struct.parse_type_name("P(3)")   #=> {:ok, "P", 3}
Dextrin.Struct.parse_type_name("P")      #=> {:ok, "P", nil}
Dextrin.Struct.parse_type_name("P(0)")   #=> :error

positional(name, values, version \\ nil, extra \\ [])

@spec positional(String.t(), [term()], pos_integer() | nil, [{term(), term()}]) :: t()

A struct written by position, at version when one is given, carrying extra.

runtime_extra(value)

@spec runtime_extra(struct()) :: [{String.t(), term()}]

The extra fields an application struct carries at run time: the keys of value its module's own defstruct does not declare, as named extras. An Elixir struct is a map, so a key put on it after the fact is the struct carrying more than it declares (DXN.md §4.7).

type_name(name, version)

@spec type_name(String.t(), pos_integer() | nil) :: String.t()

The struct's name as .dxnb writes it: Name, or Name(3) when it carries a version (DXN.md §2.4, §4.8).

Dextrin.Struct.type_name("P", 3)     #=> "P(3)"
Dextrin.Struct.type_name("P", nil)   #=> "P"