Decoder
in package
`.dxnb` decoder -- the mirror image of {@see Encoder}. Envelope (`magic` `version` `cbor_item`) checked once at the top; everything below that is a single recursive {@see self::decodeItem()}, keyed on CBOR major type first, then on tag -- matching `dxn/DXN.md` §2.2's table row order.
readHead()'s argument is always a numeric string, never a native
int -- CBOR major 0's argument can reach 2^64-1, which exceeds
PHP_INT_MAX, the same boundary Writer's own doc explains.
One case needs care that the JS port didn't: @ordered's payload
is an untagged CBOR map (major 5), and the plain, untagged major
-5 case decodes through MapBuilder (this port's own
PHP-array-key coercion for map) -- which ordered-map must NOT
go through, since its pairs can hold any key type. decodeTag()
special-cases T_ORDERED to read raw pairs directly, exactly
mirroring how Text\Parser::parseOrderedTag() avoids the same trap.
Table of Contents
Properties
- $buf : string
- $pos : int
- $registry : Registry|null
- $sharedItems : array<int, mixed>
- $stringrefStack : array<int, array<int, string>>
Methods
- decode() : mixed
- The one `.dxnb` document `$bytes` holds. Its shared-item and stringref state is its own: each document is read by a decoder of its own, so a schema check that reads a document inside a document (`encodes:`) leaves the outer one's state as it was.
- decodeSequence() : array<int, mixed>
- `$bytes` read as `.dxnb` documents back to back, each with its own envelope -- a CBOR sequence of documents, as a schema's `encodes-seq:` reads one (DXNS.md §2); no bytes at all are no documents.
- __construct() : mixed
- atTag() : bool
- Whether the next item is a tag of `$number`, without consuming it.
- buildBignum() : int|DXNInteger
- buildBits() : DXNBits|DXNBytes
- T_BITS, `[bytes, count]` (DXN.md §2.3): the count must match the bytes; a whole number of them is bytes.
- buildChar() : DXNChar
- buildCustom() : mixed
- buildDate() : DXNDate
- buildDatetime() : DXNDateTime
- buildDecimal() : DXNDecimal
- buildDuration() : DXNDuration
- `$scale` turns the seventh field into nanoseconds: 1 for tag 220, 1000 for 0.2's microseconds (tag 212).
- buildFromList() : mixed
- buildIp() : DXNIp
- RFC 9164: an address is its raw bytes; a prefix is its length and the bytes with trailing zero bytes left off, put back here.
- buildObjectId() : DXNObjectId
- buildRational() : DXNRational
- buildRegex() : DXNRegex
- The bare pattern for a regex without flags (DXN.md §2.2), or `[pattern, flags]`.
- buildStruct() : mixed
- buildTagged() : mixed
- buildTime() : DXNTime
- buildUuid() : DXNUuid
- decodeByMajor() : mixed
- decodeItem() : mixed
- decodeMajor7() : mixed
- decodeMapPairsRaw() : array<int, array{0: mixed, 1: mixed}>
- decodeNItems() : array<int, mixed>
- decodeOrderedPairs() : array<int, array{0: mixed, 1: mixed}>
- decodeShareable() : mixed
- decodeSharedRef() : mixed
- decodeStringref() : string
- decodeStringrefNamespace() : mixed
- decodeStruct() : mixed
- A struct's payload, `[type-name, field..., extras?]`, read item by item so its last item may be its extra fields: a tag-215 map (DXN.md §2.3), legal nowhere else -- anywhere else it is an unrecognized tag. Read in order, so the extras keep the order they were written in.
- decodeTag() : mixed
- decodeText() : string
- deepClone() : mixed
- Structural deep clone of a decoded value, used only to resolve a tag-29 shared-value reference into an independent copy. Every `DXN*` class here is `readonly`, so mutation-based aliasing is already structurally impossible -- this still rebuilds compound shapes (the ones with DXN-value-typed fields to recurse into) for full spec compliance and consistency with the JS port's own (mutable-object) behavior; scalar-only-field classes have nothing to alias and are returned as-is.
- document() : array{0: mixed, 1: int}
- The document at `$at` in `$bytes`, and the offset just past it.
- expectString() : mixed
- integerAsString() : numeric-string
- orderedMap() : DXNOrderedMap
- An ordered map, every key one DXN.md §1.6 allows.
- pair() : array{0: int, 1: int}
- A datetime payload, `[epoch, offset-minutes]`, the epoch times `$scale`.
- readByte() : int
- readHead() : array{0: int, 1: numeric-string}
- registerStringref() : void
- requireInteger() : int|DXNInteger
- requireSmallInt() : int
- scaled() : int
- An integer payload times `$scale`: 0.2's microseconds as nanoseconds.
- smallIndexOrNull() : int|null
- take() : string
- unpackFloat() : float
- unpackUint() : int
Properties
$buf read-only
private
string
$buf
$pos
private
int
$pos
$registry
private
Registry|null
$registry
$sharedItems
private
array<int, mixed>
$sharedItems
= []
indexed by tag-28 registration order.
$stringrefStack
private
array<int, array<int, string>>
$stringrefStack
= []
innermost scope last.
Methods
decode()
The one `.dxnb` document `$bytes` holds. Its shared-item and stringref state is its own: each document is read by a decoder of its own, so a schema check that reads a document inside a document (`encodes:`) leaves the outer one's state as it was.
public
static decode(string $bytes[, Registry|null $registry = null ]) : mixed
Parameters
- $bytes : string
- $registry : Registry|null = null
decodeSequence()
`$bytes` read as `.dxnb` documents back to back, each with its own envelope -- a CBOR sequence of documents, as a schema's `encodes-seq:` reads one (DXNS.md §2); no bytes at all are no documents.
public
static decodeSequence(string $bytes[, Registry|null $registry = null ]) : array<int, mixed>
Parameters
- $bytes : string
- $registry : Registry|null = null
Return values
array<int, mixed>__construct()
private
__construct(string $buf, int $pos, Registry|null $registry) : mixed
Parameters
- $buf : string
- $pos : int
- $registry : Registry|null
atTag()
Whether the next item is a tag of `$number`, without consuming it.
private
atTag(int $number) : bool
Parameters
- $number : int
Tags
Return values
boolbuildBignum()
private
buildBignum(mixed $value, int $tag, bool $negative) : int|DXNInteger
Parameters
- $value : mixed
- $tag : int
- $negative : bool
Return values
int|DXNIntegerbuildBits()
T_BITS, `[bytes, count]` (DXN.md §2.3): the count must match the bytes; a whole number of them is bytes.
private
buildBits(mixed $value) : DXNBits|DXNBytes
Parameters
- $value : mixed
Return values
DXNBits|DXNBytesbuildChar()
private
buildChar(mixed $value) : DXNChar
Parameters
- $value : mixed
Return values
DXNCharbuildCustom()
private
buildCustom(mixed $value) : mixed
Parameters
- $value : mixed
buildDate()
private
buildDate(mixed $value) : DXNDate
Parameters
- $value : mixed
Return values
DXNDatebuildDatetime()
private
buildDatetime(array{0: int, 1: int} $parts, int $tag) : DXNDateTime
Parameters
- $parts : array{0: int, 1: int}
- $tag : int
Return values
DXNDateTimebuildDecimal()
private
buildDecimal(mixed $value) : DXNDecimal
Parameters
- $value : mixed
Return values
DXNDecimalbuildDuration()
`$scale` turns the seventh field into nanoseconds: 1 for tag 220, 1000 for 0.2's microseconds (tag 212).
private
buildDuration(mixed $value, int $tag, int $scale) : DXNDuration
Parameters
- $value : mixed
- $tag : int
- $scale : int
Return values
DXNDurationbuildFromList()
private
buildFromList(mixed $value, int $tag, string $name, callable(array<int, mixed>): mixed $build) : mixed
Parameters
- $value : mixed
- $tag : int
- $name : string
- $build : callable(array<int, mixed>): mixed
buildIp()
RFC 9164: an address is its raw bytes; a prefix is its length and the bytes with trailing zero bytes left off, put back here.
private
buildIp(mixed $value, int $tag, int $size) : DXNIp
Parameters
- $value : mixed
- $tag : int
- $size : int
Return values
DXNIpbuildObjectId()
private
buildObjectId(mixed $value) : DXNObjectId
Parameters
- $value : mixed
Return values
DXNObjectIdbuildRational()
private
buildRational(mixed $value) : DXNRational
Parameters
- $value : mixed
Return values
DXNRationalbuildRegex()
The bare pattern for a regex without flags (DXN.md §2.2), or `[pattern, flags]`.
private
buildRegex(mixed $value) : DXNRegex
Parameters
- $value : mixed
Return values
DXNRegexbuildStruct()
private
buildStruct(array<int, mixed> $items, array<int, array{0: mixed, 1: mixed}> $extra) : mixed
Parameters
- $items : array<int, mixed>
-
the type name, then the fields.
- $extra : array<int, array{0: mixed, 1: mixed}>
buildTagged()
private
buildTagged(int $tag, mixed $value) : mixed
Parameters
- $tag : int
- $value : mixed
buildTime()
private
buildTime(int $nanos) : DXNTime
Parameters
- $nanos : int
Return values
DXNTimebuildUuid()
private
buildUuid(mixed $value) : DXNUuid
Parameters
- $value : mixed
Return values
DXNUuiddecodeByMajor()
private
decodeByMajor(int $major, numeric-string $arg) : mixed
Parameters
- $major : int
- $arg : numeric-string
decodeItem()
private
decodeItem() : mixed
decodeMajor7()
private
decodeMajor7(int $info) : mixed
Parameters
- $info : int
decodeMapPairsRaw()
private
decodeMapPairsRaw(int $pairCount) : array<int, array{0: mixed, 1: mixed}>
Parameters
- $pairCount : int
Return values
array<int, array{0: mixed, 1: mixed}>decodeNItems()
private
decodeNItems(int $count) : array<int, mixed>
Parameters
- $count : int
Tags
Return values
array<int, mixed>decodeOrderedPairs()
private
decodeOrderedPairs() : array<int, array{0: mixed, 1: mixed}>
Return values
array<int, array{0: mixed, 1: mixed}>decodeShareable()
private
decodeShareable() : mixed
decodeSharedRef()
private
decodeSharedRef() : mixed
decodeStringref()
private
decodeStringref() : string
Return values
stringdecodeStringrefNamespace()
private
decodeStringrefNamespace() : mixed
decodeStruct()
A struct's payload, `[type-name, field..., extras?]`, read item by item so its last item may be its extra fields: a tag-215 map (DXN.md §2.3), legal nowhere else -- anywhere else it is an unrecognized tag. Read in order, so the extras keep the order they were written in.
private
decodeStruct() : mixed
decodeTag()
private
decodeTag(int $tagNumber) : mixed
Parameters
- $tagNumber : int
decodeText()
private
decodeText(int $len) : string
Parameters
- $len : int
Return values
stringdeepClone()
Structural deep clone of a decoded value, used only to resolve a tag-29 shared-value reference into an independent copy. Every `DXN*` class here is `readonly`, so mutation-based aliasing is already structurally impossible -- this still rebuilds compound shapes (the ones with DXN-value-typed fields to recurse into) for full spec compliance and consistency with the JS port's own (mutable-object) behavior; scalar-only-field classes have nothing to alias and are returned as-is.
private
static deepClone(mixed $value) : mixed
Parameters
- $value : mixed
document()
The document at `$at` in `$bytes`, and the offset just past it.
private
static document(string $bytes, int $at, Registry|null $registry) : array{0: mixed, 1: int}
Parameters
- $bytes : string
- $at : int
- $registry : Registry|null
Return values
array{0: mixed, 1: int}expectString()
private
expectString(mixed $value, int $tag, string $name, callable(string): mixed $build) : mixed
Parameters
- $value : mixed
- $tag : int
- $name : string
- $build : callable(string): mixed
integerAsString()
private
integerAsString(int|DXNInteger $value) : numeric-string
Parameters
- $value : int|DXNInteger
Return values
numeric-stringorderedMap()
An ordered map, every key one DXN.md §1.6 allows.
private
static orderedMap(array<int, array{0: mixed, 1: mixed}> $pairs) : DXNOrderedMap
Parameters
- $pairs : array<int, array{0: mixed, 1: mixed}>
Return values
DXNOrderedMappair()
A datetime payload, `[epoch, offset-minutes]`, the epoch times `$scale`.
private
pair(mixed $value, int $tag, int $scale) : array{0: int, 1: int}
Parameters
- $value : mixed
- $tag : int
- $scale : int
Return values
array{0: int, 1: int}readByte()
private
readByte() : int
Return values
intreadHead()
private
readHead() : array{0: int, 1: numeric-string}
Tags
Return values
array{0: int, 1: numeric-string}registerStringref()
private
registerStringref(string $text) : void
Parameters
- $text : string
requireInteger()
private
requireInteger(mixed $value, int $tag, string $name) : int|DXNInteger
Parameters
- $value : mixed
- $tag : int
- $name : string
Return values
int|DXNIntegerrequireSmallInt()
private
requireSmallInt(mixed $value, int $tag, string $name) : int
Parameters
- $value : mixed
- $tag : int
- $name : string
Return values
intscaled()
An integer payload times `$scale`: 0.2's microseconds as nanoseconds.
private
scaled(mixed $value, int $tag, string $name, int $scale) : int
Parameters
- $value : mixed
- $tag : int
- $name : string
- $scale : int
Return values
intsmallIndexOrNull()
private
smallIndexOrNull(mixed $value) : int|null
Parameters
- $value : mixed
Return values
int|nulltake()
private
take(int $len) : string
Parameters
- $len : int
Return values
stringunpackFloat()
private
static unpackFloat(string $bytes, string $format) : float
Parameters
- $bytes : string
- $format : string
Return values
floatunpackUint()
private
static unpackUint(string $bytes, string $format) : int
Parameters
- $bytes : string
- $format : string