//! The atproto data model, its canonical encoding, and the CIDs that names. //! //! atproto's records are exchanged as JSON and *identified* as DAG-CBOR. The //! two are the same data model wearing different clothes, and the identity of //! a record — the CID a commit signs, a link quotes and an MST keys on — is //! the sha-256 of the DAG-CBOR bytes. Everything downstream of that hash //! depends on there being exactly one such encoding per record, which is why //! this crate is three narrow pieces rather than a serializer: //! //! * [`Value`] is the data model: the values that *have* an encoding, and //! nothing else. Building one from JSON is where every rejection happens. //! * [`dag_cbor`] turns one into bytes, and cannot fail. It reads them back //! too, which is a stricter job: see [`dag_cbor::decode`]. //! * [`Cid`] is the hash of those bytes, and the only string form atproto //! permits for it. //! //! * [`mst`] is the fourth piece and the largest: the Merkle search tree a //! repository is keyed by, along with the two pure functions its shape //! comes from. //! //! ``` //! use didbot_data::{dag_cbor, Value}; //! //! let record = serde_json::json!({ //! "$type": "com.example.thing", //! "text": "quernstone", //! "count": 1, //! }); //! let value = Value::object_from_json(&record).expect("a data-model record"); //! let bytes = dag_cbor::encode(&value); //! assert_eq!(dag_cbor::cid(&value), didbot_data::Cid::of_dag_cbor(&bytes)); //! ``` //! //! # Why this is its own crate //! //! It sits below everything that would use it and depends on none of them. A //! repository needs it to name a record, a Merkle search tree needs it to key //! one, a commit needs it to sign one, and a CAR file needs it to frame one. //! The tree is here, because a tree is nothing but keys and the encoding of //! its own nodes; the commit and the CAR are in `didbot-repo`, because //! they need a signing key and this crate deliberately depends on nothing. //! //! # What this crate does not do //! //! It is not a `serde` data format: records arrive here as `serde_json::Value` from //! an HTTP body, and a derive-driven path would only add a second way to //! produce bytes that must be identical to these. //! //! The conformance suite this is held to is `data-model/` in the vendored //! upstream vectors; see `docs/conformance.md`. #![forbid(unsafe_code)] pub mod cid; pub mod dag_cbor; mod encoding; pub mod mst; pub mod value; pub use cid::{Cid, CidError, RawHasher}; pub use value::{DataError, ErrorKind, Value};