1#![forbid(unsafe_code)]
2#![deny(missing_docs)]
3use serde::{de::DeserializeOwned, Serialize};
11use std::io::Read;
12use thiserror::Error;
13
14pub mod binary;
15pub use binary::{
16 decode_frame, decode_varint_u64, encode_frame, encode_varint_u64, BinaryCodecError, Decoder,
17 Encoder, T_BYTES, T_CID32, T_PUBKEY32, T_SIG64, T_STR, T_U64,
18};
19
20#[derive(Debug, Error)]
22pub enum AtomicCodecError {
23 #[error("serde: {0}")]
25 Serde(#[from] serde_json::Error),
26 #[error("canon: {0}")]
28 Canon(String),
29 #[error("yaml: {0}")]
31 Yaml(String),
32}
33
34pub fn to_canon_vec<T: Serialize>(v: &T) -> Result<Vec<u8>, AtomicCodecError> {
41 let val = serde_json::to_value(v)?;
42 json_atomic::canonize(&val).map_err(|e| AtomicCodecError::Canon(e.to_string()))
43}
44
45pub fn from_canon_slice<T: DeserializeOwned>(bytes: &[u8]) -> Result<T, AtomicCodecError> {
51 Ok(serde_json::from_slice(bytes)?)
52}
53
54pub fn from_json_str_canon(s: &str) -> Result<Vec<u8>, AtomicCodecError> {
61 let v: serde_json::Value = serde_json::from_str(s)?;
62 json_atomic::canonize(&v).map_err(|e| AtomicCodecError::Canon(e.to_string()))
63}
64
65pub fn to_cid_hex<T: Serialize>(v: &T) -> Result<String, AtomicCodecError> {
71 let b = to_canon_vec(v)?;
72 Ok(blake3::hash(&b).to_hex().to_string())
73}
74
75pub struct Canonical<T> {
77 value: T,
78 bytes: Vec<u8>,
79}
80impl<T> Canonical<T>
81where
82 T: Serialize + DeserializeOwned,
83{
84 pub fn new(value: T) -> Result<Self, AtomicCodecError> {
91 let bytes = to_canon_vec(&value)?;
92 Ok(Self { value, bytes })
93 }
94 pub fn from_reader<R: Read>(mut r: R) -> Result<Self, AtomicCodecError> {
101 let mut s = String::new();
102 r.read_to_string(&mut s)
103 .map_err(|e| AtomicCodecError::Canon(e.to_string()))?;
104 let v: serde_json::Value = serde_json::from_str(&s)?;
105 let bytes =
106 json_atomic::canonize(&v).map_err(|e| AtomicCodecError::Canon(e.to_string()))?;
107 Ok(Self {
108 value: serde_json::from_value(v)?,
109 bytes,
110 })
111 }
112 pub const fn value(&self) -> &T {
114 &self.value
115 }
116 pub fn as_bytes(&self) -> &[u8] {
118 &self.bytes
119 }
120 pub fn into_bytes(self) -> Vec<u8> {
122 self.bytes
123 }
124}
125
126#[must_use]
128pub fn is_canonical(s: &str) -> bool {
129 serde_json::from_str::<serde_json::Value>(s)
130 .ok()
131 .and_then(|v| json_atomic::canonize(&v).ok())
132 .and_then(|b| String::from_utf8(b).ok())
133 .is_some_and(|canon| canon == s.trim())
134}
135
136pub fn yaml_to_canon_vec(yaml: &str) -> Result<Vec<u8>, AtomicCodecError> {
143 let v: serde_json::Value = match serde_yaml::from_str::<serde_yaml::Value>(yaml) {
144 Ok(doc) => serde_json::to_value(doc).map_err(|e| AtomicCodecError::Yaml(e.to_string()))?,
145 Err(e) => return Err(AtomicCodecError::Yaml(e.to_string())),
146 };
147 json_atomic::canonize(&v).map_err(|e| AtomicCodecError::Canon(e.to_string()))
148}