The objects plugin stores binary payloads in the database file and names them in a tree of files and directories.
Enable it at open with plugins {objects {}}. It has no settings.
See plugin selection for the open options.
Calls without it report the unavailable status.
The typed wrappers use plugin_call or plugin_stream with plugin objects.
Request members use lowerCamelCase, such as expectedRevision.
A payload is an immutable byte sequence. Its digest is the SHA-256 of all its bytes.
Write a payload through an upload stream: write appends bytes in order and finish publishes the payload atomically.
Equal bytes publish one payload: a second finish of the same bytes reports deduplicated true and stores nothing new.
The database splits payloads into content-defined chunks of 256 KiB to 4 MiB, so edits to a large payload share most chunks with earlier versions.
manifest lists the chunks, and an open stream reads any byte range: seek moves its position and read copies from it.
Published payloads are never deleted. Removing a file or pointing it at another payload keeps the earlier payload, and history keeps every earlier version of the file.
An upload that does not finish publishes nothing. Closing the stream abandons it, and the next open removes what an interrupted upload left behind.
Each upload holds a working buffer of up to 4 MiB from the database memory budget until it finishes or closes.
An upload that cannot fit reports out_of_memory. Calls on one stream are serialized; separate streams can run at the same time.
Digests cross the API as 64 hexadecimal digits in either case. Results show them as {#sha256 <hex>} values.
Every node lives under the root directory, entity 0. A directory holds named children; a file names one published payload.
Names are non-empty UTF-8 text without / or NUL, and are not . or ... Names are unique within a directory and hold at most 4096 bytes.
A record describes one node:
Member
Value
entity
The node's entity.
parent
The parent directory's entity, 0 for the root.
name
The node's name in its parent.
kind
file or directory.
revision
The transaction that last changed the node.
size
A file's payload size in bytes.
digest
A file's payload digest.
create creates up to 4096 nodes in one commit.
A node names its parent by entity, or with under by the position of an earlier directory in the same request:
A file can name only a published payload.
A merge patch can also write stardust/object/digest on an entity; the commit then needs a published payload too.
Each write commits atomically through the commit queue. A refused write changes nothing.
update, move and remove take an expected revision.
Pass the revision of a record you read to refuse the write when another writer changed the node since: the call reports conflict.
Pass 0 to skip the check.
An update to the current payload, or a move to the current name and parent, changes nothing and keeps the revision.
With replace true, a move can replace a destination node of the same kind.
A file replaces a file. A directory replaces only an empty directory.
Remove deletes a file or an empty directory.
Every tree read uses one snapshot of the database. Concurrent writes do not change a read in progress.
children lists a directory in name order.
path returns the names from the root to a node.
files finds the files that hold a payload.
A stream read verifies every chunk it reads against its digest and reports evaluation_failed when stored bytes do not match.
On a database that does not enable objects, a write that sets stardust/object/digest fails with the unavailable status and the code plugin_required.
Payloads and files that the plugin stored stay in the database file and return when the plugin is enabled again.
A borrowed array of at most 4096 nodes. Each has name, and parent (entity, default 0) or under (one-based position of an earlier directory). A file also has digest {#sha256 hex}. Without digest, the node is a directory.
letmut upload = db.objects().upload()?;
upload.write(b"Hello, objects")?;
upload.finish()?;
upload.close();// under 1 places hello.txt in the first node of the request.let nodes = stardust::parse(r#"[{name notes} {name hello.txt under 1 digest {#sha256 "95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb"}}]"#,Format::DUST)?;let result = db.objects().create(&nodes)?;
for text in[&b"Hello, objects"[..],&b"Revised notes"[..]]{letmut upload = db.objects().upload()?;
upload.write(text)?;
upload.finish()?;}let nodes = stardust::parse(r#"[{name hello.txt digest {#sha256 "95e84da38cbefdf3f9f6ef02201074c73124f7cf2025d3e1d69e591a410856fb"}}]"#,Format::DUST)?;
db.objects().create(&nodes)?;// 0 skips the revision check; pass a record's revision to refuse a stale write.let result = db.objects().update(1,"2b6d3a4299dac5900171112d4fd569b48e54711d8937f6ff5ca00528d47afad2",0)?;
With replace, a node of the same kind at the destination is replaced; a directory only when it is empty. A move into the node's own subtree is invalid.
db.objects().create(&stardust::parse("[{name notes} {name drafts}]",Format::DUST)?)?;// false refuses to replace a node that already has the name.let result = db.objects().r#move(2,1,"archive",0,false)?;
The stream holds a working buffer of up to 4 MiB from the database memory budget until it finishes or closes. Write appends bytes; finish publishes the payload and returns {digest size deduplicated}.
// Dropping the upload abandons it unless it finished.letmut upload = db.objects().upload()?;// The upload stream implements std::io::Write, so std::io::copy can stream into it.
std::io::copy(&mut&b"Hello, objects"[..],&mut upload)?;let result = upload.finish()?;
Read copies bytes from the position and verifies each chunk it touches; seek moves the position, from the end with the payload size. The reader charges its state to the database memory budget until it is released or the database closes.