Skip to main content

lace_sans_io/records/
mod.rs

1//! Lace H3 record creation, validation, and metadata views.
2
3pub(crate) mod blob;
4pub(crate) mod erasure;
5pub(crate) mod file;
6pub(crate) mod hash;
7pub(crate) mod metadata;
8pub(crate) mod plex;
9pub(crate) mod record;
10pub(crate) mod seal;
11pub(crate) mod spec;
12pub(crate) mod typed_text;
13pub(crate) mod util;
14pub(crate) mod validator;
15
16#[cfg(test)]
17mod layout_tests;
18
19pub use b64a::{b64a_decode, b64a_decoded_len, b64a_encode, b64a_encoded_len};
20pub use schnorr_blake3::{CryptoError, Mark, SigningKey, VerificationKey};
21
22/// Plain BLAKE3 hash of data.
23pub fn blake3_hash(data: &[u8]) -> [u8; 32] {
24    blake3::hash(data).into()
25}
26
27/// Generate nonzero auxiliary randomness using the OS random source.
28pub fn random_aux_rand32() -> Result<[u8; 32], getrandom::Error> {
29    loop {
30        let mut aux = zeroize::Zeroizing::new([0; 32]);
31        getrandom::fill(&mut *aux)?;
32        if *aux != [0; 32] {
33            return Ok(*aux);
34        }
35    }
36}
37pub use hash::{HashTextError, RECORD_HASH_B64A_LEN, RECORD_HASH_TEXT_LEN, RecordHash, RecordKind};
38pub use metadata::{ApplicationFieldIter, FieldOccurrence, IndexedField, RecordMetadata};
39pub use record::{Record, RecordReadError};
40pub use validator::{RecordError, RecordValidator, ValidatedHeader};
41
42/// Internal exact-auxiliary construction used by protocol hosts and fixtures.
43#[cfg(feature = "internal")]
44#[doc(hidden)]
45pub mod internal {
46    /// Derive exact auxiliary bytes for reproducible protocol fixtures.
47    pub fn derive_aux_rand32(input: &[u8]) -> [u8; 32] {
48        blake3::derive_key("lace-🖧/deterministic-aux", input)
49    }
50    pub use super::spec::new_record_with_aux_rand32;
51}
52
53pub use spec::{IntoRecordData, RecordCreateError, RecordSpec, new_record};
54pub use typed_text::{
55    BY_SECRET_TEXT_LEAD, BY_VALUE_TEXT_LEAD, BySecret, ByValue, REGISTERED_TYPED_TEXT_LEADS,
56    TypedH3Text, TypedTextError, generate_by_secret, typed_text_lead_description,
57};
58pub(crate) use util::validate_projected_field_name_value;
59pub use util::{
60    LENGTH_FIELD, MAX_BLOB_RECORD_BYTES, MAX_BLOB_SIZE, MAX_FIELD_LINE_BYTES_EXCLUDING_LF,
61    MAX_H3_RECORD_BYTES, MAX_PLEX_FIELDS, MAX_PLEX_RECORD_BYTES, MAX_RECORD_METADATA_BYTES,
62    RECORD_GLYPH, SYNTHETIC_FIELD_NAMES, TYPE_FIELD, is_synthetic_field_name,
63};
64
65/// Convert owned or borrowed validated records into a store-operation batch.
66pub trait IntoRecordBatch {
67    fn into_records(self) -> Vec<Record>;
68}
69
70impl IntoRecordBatch for Record {
71    fn into_records(self) -> Vec<Record> {
72        vec![self]
73    }
74}
75impl IntoRecordBatch for &Record {
76    fn into_records(self) -> Vec<Record> {
77        vec![self.clone()]
78    }
79}
80impl IntoRecordBatch for Vec<Record> {
81    fn into_records(self) -> Vec<Record> {
82        self
83    }
84}
85impl IntoRecordBatch for &[Record] {
86    fn into_records(self) -> Vec<Record> {
87        self.to_vec()
88    }
89}
90impl<const N: usize> IntoRecordBatch for [Record; N] {
91    fn into_records(self) -> Vec<Record> {
92        Vec::from(self)
93    }
94}
95
96#[doc(hidden)]
97#[macro_export]
98macro_rules! __lace_record_spec_apply {
99    ($spec:ident $(,)?) => {};
100    ($spec:ident, by_secret: $value:expr $(, $($rest:tt)*)?) => {{
101        $spec = $spec.by_secret($value);
102        $crate::__lace_record_spec_apply!($spec $(, $($rest)*)?);
103    }};
104    ($spec:ident, data: $value:expr $(, $($rest:tt)*)?) => {{
105        $spec = $spec.data($value);
106        $crate::__lace_record_spec_apply!($spec $(, $($rest)*)?);
107    }};
108    ($spec:ident, fields: { $( $name:literal : $value:expr ),* $(,)? } $(, $($rest:tt)*)?) => {{
109        $(
110            $spec = $spec.field($name, $value);
111        )*
112        $crate::__lace_record_spec_apply!($spec $(, $($rest)*)?);
113    }};
114    ($spec:ident, fields: [ $( ( $name:expr, $value:expr ) ),* $(,)? ] $(, $($rest:tt)*)?) => {{
115        $(
116            $spec = $spec.field($name, $value);
117        )*
118        $crate::__lace_record_spec_apply!($spec $(, $($rest)*)?);
119    }};
120    ($spec:ident, fields: $value:expr $(, $($rest:tt)*)?) => {{
121        $spec = $spec.fields($value);
122        $crate::__lace_record_spec_apply!($spec $(, $($rest)*)?);
123    }};
124}
125
126/// Build a [`RecordSpec`](crate::records::RecordSpec) from Rust literal syntax.
127#[macro_export]
128macro_rules! spec {
129    ({ $($body:tt)* }) => {{
130        let mut __lace_record_spec = $crate::records::RecordSpec::new();
131        $crate::__lace_record_spec_apply!(__lace_record_spec, $($body)*);
132        __lace_record_spec
133    }};
134    ($base:expr, { $($body:tt)* }) => {{
135        let mut __lace_record_spec = ($base).clone();
136        $crate::__lace_record_spec_apply!(__lace_record_spec, $($body)*);
137        __lace_record_spec
138    }};
139}
140
141/// Build and validate a record from a [`RecordSpec`](crate::records::RecordSpec) literal.
142#[macro_export]
143macro_rules! record {
144    ({ $($body:tt)* }) => {{
145        $crate::records::new_record($crate::spec!({ $($body)* }))
146    }};
147    ($base:expr, { $($body:tt)* }) => {{
148        $crate::records::new_record($crate::spec!($base, { $($body)* }))
149    }};
150}