Skip to main content

coven_format/
merge_fields.rs

1//! Unframed fields of snapshot merge metadata, also used in coven's SQLite blobs.
2//!
3//! These are the same bytes as the corresponding snapshot fields, using the
4//! shared bounded encoder and decoder. The containing database schema or frame
5//! supplies the format version. Decoders reject trailing bytes and malformed
6//! fields; relationships between fields and writes remain merge's responsibility.
7
8use crate::wire::{Decoder, Encoder, Wire};
9use crate::{merge_wire, value::Value, Error};
10use coven_merge::{ColumnValue, Rule, Timestamp, WriteId};
11use std::collections::{BTreeMap, BTreeSet};
12
13fn encode<T: Wire>(value: &T) -> Result<Vec<u8>, Error> {
14    let mut out = Encoder::new();
15    value.put(&mut out)?;
16    Ok(out.bytes)
17}
18
19fn decode<T: Wire>(bytes: &[u8]) -> Result<T, Error> {
20    decode_with(bytes, T::get)
21}
22
23fn decode_with<T, E: From<Error>>(
24    bytes: &[u8],
25    get: impl FnOnce(&mut Decoder<'_>) -> Result<T, E>,
26) -> Result<T, E> {
27    let mut input = Decoder::new(bytes)?;
28    let value = get(&mut input)?;
29    input.finish()?;
30    Ok(value)
31}
32
33/// Encode a write timestamp using its snapshot field bytes.
34pub fn encode_timestamp(value: &Timestamp) -> Result<Vec<u8>, Error> {
35    encode(value)
36}
37
38/// Decode exactly one snapshot field containing a write timestamp.
39pub fn decode_timestamp(bytes: &[u8]) -> Result<Timestamp, Error> {
40    let value: Timestamp = decode(bytes)?;
41    Ok(value)
42}
43
44/// Encode a setter or replacing write using its snapshot field bytes.
45pub fn encode_write_id(value: &WriteId) -> Result<Vec<u8>, Error> {
46    crate::value::positive(value.number)?;
47    encode(value)
48}
49
50/// Decode exactly one snapshot field containing a setter or replacing write.
51pub fn decode_write_id(bytes: &[u8]) -> Result<WriteId, Error> {
52    let value: WriteId = decode(bytes)?;
53    crate::value::positive(value.number)?;
54    Ok(value)
55}
56
57/// Encode an original row change's identity using its D5 field bytes.
58pub fn encode_change_id(value: &crate::write_sources::ChangeId) -> Result<Vec<u8>, Error> {
59    crate::value::positive(value.write.number)?;
60    crate::value::row(&value.row)?;
61    encode(value)
62}
63
64/// Decode exactly one original row change identity.
65pub fn decode_change_id(bytes: &[u8]) -> Result<crate::write_sources::ChangeId, Error> {
66    let value: crate::write_sources::ChangeId = decode(bytes)?;
67    crate::value::positive(value.write.number)?;
68    crate::value::row(&value.row)?;
69    Ok(value)
70}
71
72/// Encode a retained authorship opening using its D7 field bytes.
73pub fn encode_multiproof(value: &crate::authorship::Multiproof) -> Result<Vec<u8>, Error> {
74    encode(value)
75}
76
77/// Decode a retained authorship opening.
78pub fn decode_multiproof(bytes: &[u8]) -> Result<crate::authorship::Multiproof, Error> {
79    decode(bytes)
80}
81
82/// Encode a foreign key's stable identity using its snapshot field bytes.
83pub fn encode_foreign_key(value: &coven_merge::ForeignKey) -> Result<Vec<u8>, Error> {
84    merge_wire::foreign_key(value)?;
85    encode(value)
86}
87
88/// Decode exactly one foreign key identity.
89pub fn decode_foreign_key(bytes: &[u8]) -> Result<coven_merge::ForeignKey, Error> {
90    let value = decode(bytes)?;
91    merge_wire::foreign_key(&value)?;
92    Ok(value)
93}
94
95/// Encode a unique constraint's terms and partial predicate.
96pub fn encode_unique_constraint(value: &coven_merge::UniqueConstraint) -> Result<Vec<u8>, Error> {
97    merge_wire::unique_constraint(value)?;
98    encode(value)
99}
100
101/// Decode exactly one unique constraint identity.
102pub fn decode_unique_constraint(bytes: &[u8]) -> Result<coven_merge::UniqueConstraint, Error> {
103    let value = decode(bytes)?;
104    merge_wire::unique_constraint(&value)?;
105    Ok(value)
106}
107
108/// Encode a lost cell value and its parents using its snapshot field bytes.
109pub fn encode_column_value(value: &ColumnValue<Value>) -> Result<Vec<u8>, Error> {
110    merge_wire::column(value)?;
111    encode(value)
112}
113
114/// Decode exactly one snapshot field containing a lost cell value and its parents.
115pub fn decode_column_value(bytes: &[u8]) -> Result<ColumnValue<Value>, Error> {
116    let value: ColumnValue<Value> = decode(bytes)?;
117    merge_wire::column(&value)?;
118    Ok(value)
119}
120
121/// Encode a removed row’s values and parents using its snapshot field bytes.
122pub fn encode_columns(value: &BTreeMap<String, ColumnValue<Value>>) -> Result<Vec<u8>, Error> {
123    merge_wire::columns(value)?;
124    encode(value)
125}
126
127/// Decode exactly one snapshot field containing a removed row’s values and parents.
128pub fn decode_columns(bytes: &[u8]) -> Result<BTreeMap<String, ColumnValue<Value>>, Error> {
129    let value = decode_with(bytes, crate::wire::get_name_map)?;
130    merge_wire::columns(&value)?;
131    Ok(value)
132}
133
134/// Encode a removed row’s setters using its snapshot field bytes.
135pub fn encode_setters(value: &BTreeMap<String, WriteId>) -> Result<Vec<u8>, Error> {
136    merge_wire::setters(value)?;
137    encode(value)
138}
139
140/// Decode exactly one snapshot field containing a removed row’s setters.
141pub fn decode_setters(bytes: &[u8]) -> Result<BTreeMap<String, WriteId>, Error> {
142    let value = decode_with(bytes, crate::wire::get_name_map)?;
143    merge_wire::setters(&value)?;
144    Ok(value)
145}
146
147/// Encode removal rules using its snapshot field bytes.
148pub fn encode_rules(value: &BTreeSet<Rule>) -> Result<Vec<u8>, Error> {
149    merge_wire::rules(value)?;
150    encode(value)
151}
152
153/// Decode exactly one snapshot field containing removal rules.
154pub fn decode_rules(bytes: &[u8]) -> Result<BTreeSet<Rule>, Error> {
155    let value: BTreeSet<Rule> = decode(bytes)?;
156    merge_wire::rules(&value)?;
157    Ok(value)
158}
159
160/// Encode the excluded write and the breaking schema version that excluded it.
161pub fn encode_exclusion(write: WriteId, version: u32) -> Result<Vec<u8>, Error> {
162    crate::value::positive(write.number)?;
163    crate::error::require(version > 0, "breaking schema version", crate::error::Rule::Required)?;
164    let mut out = Encoder::new();
165    write.put(&mut out)?;
166    version.put(&mut out)?;
167    Ok(out.bytes)
168}
169
170/// Decode an excluded write's identity and breaking version from its loss record.
171pub fn decode_exclusion(bytes: &[u8]) -> Result<(WriteId, u32), Error> {
172    let (write, version): (WriteId, u32) =
173        decode_with(bytes, |input| Ok::<_, Error>((Wire::get(input)?, Wire::get(input)?)))?;
174    crate::value::positive(write.number)?;
175    crate::error::require(version > 0, "breaking schema version", crate::error::Rule::Required)?;
176    Ok((write, version))
177}
178
179/// Encode a dependent change's write and failed sources for its loss record.
180pub fn encode_dependency(
181    write: WriteId,
182    sources: &[crate::write_sources::ChangeId],
183) -> Result<Vec<u8>, Error> {
184    let mut out = Encoder::new();
185    write.put(&mut out)?;
186    sources.to_vec().put(&mut out)?;
187    Ok(out.bytes)
188}
189
190/// Decode a dependent change's write and failed sources.
191pub fn decode_dependency(
192    bytes: &[u8],
193) -> Result<(WriteId, Vec<crate::write_sources::ChangeId>), Error> {
194    let (write, sources): (WriteId, Vec<crate::write_sources::ChangeId>) =
195        decode_with(bytes, |input| Ok::<_, Error>((Wire::get(input)?, Wire::get(input)?)))?;
196    crate::value::positive(write.number)?;
197    Ok((write, sources))
198}
199
200/// Encode an unauthorized change's write and reason for its loss record.
201pub fn encode_unauthorized(
202    write: WriteId,
203    reason: &crate::loss::AuthorizationFailure,
204) -> Result<Vec<u8>, Error> {
205    crate::value::positive(write.number)?;
206    let mut out = Encoder::new();
207    write.put(&mut out)?;
208    reason.put(&mut out)?;
209    Ok(out.bytes)
210}
211
212/// Decode an unauthorized change's write and reason.
213pub fn decode_unauthorized(
214    bytes: &[u8],
215) -> Result<(WriteId, crate::loss::AuthorizationFailure), Error> {
216    let (write, reason): (WriteId, crate::loss::AuthorizationFailure) =
217        decode_with(bytes, |input| Ok::<_, Error>((Wire::get(input)?, Wire::get(input)?)))?;
218    crate::value::positive(write.number)?;
219    Ok((write, reason))
220}
221
222/// Encode a change's verdict with the bytes its snapshot evidence uses.
223pub fn encode_change_verdict(
224    value: &crate::snapshot_rows::ChangeVerdict,
225) -> Result<Vec<u8>, Error> {
226    value.validate()?;
227    encode(value)
228}
229
230/// Decode a change's verdict stored with its original change.
231pub fn decode_change_verdict(bytes: &[u8]) -> Result<crate::snapshot_rows::ChangeVerdict, Error> {
232    let value: crate::snapshot_rows::ChangeVerdict = decode(bytes)?;
233    value.validate()?;
234    Ok(value)
235}
236
237/// Encode one loss using the same bytes as the snapshot loss section.
238pub fn encode_loss(value: &crate::loss::Loss) -> Result<Vec<u8>, Error> {
239    value.validate()?;
240    encode(value)
241}
242
243/// Decode one retained loss using the snapshot loss fields.
244pub fn decode_loss(bytes: &[u8]) -> Result<crate::loss::Loss, Error> {
245    let value: crate::loss::Loss = decode(bytes)?;
246    value.validate()?;
247    Ok(value)
248}
249
250/// Encode retained generations and winning cells using the snapshot merge fields.
251pub fn encode_merge_row(value: &crate::snapshot_rows::MergeRow) -> Result<Vec<u8>, Error> {
252    value.validate()?;
253    let mut out = Encoder::new();
254    value.put(&mut out)?;
255    Ok(out.bytes)
256}
257
258/// Decode a retained merge row against its original checked write metadata.
259pub fn decode_merge_row<O: coven_merge::WriteOracle>(
260    bytes: &[u8],
261    oracle: &O,
262) -> Result<crate::snapshot_rows::MergeRow, O::Error>
263where
264    O::Error: From<Error>,
265{
266    let value = decode_with(bytes, |input| crate::snapshot_rows::MergeRow::get(input, oracle))?;
267    value.validate()?;
268    Ok(value)
269}
270
271/// Encode a received write header for local retention, using its D5 field bytes.
272/// The receiving transaction checks the write; a refused write commits nothing.
273pub fn encode_write_header(value: &crate::write::WriteHeader) -> Result<Vec<u8>, Error> {
274    encode(value)
275}
276
277/// Decode a retained write header. Its checks ran when the write was accepted.
278pub fn decode_write_header(bytes: &[u8]) -> Result<crate::write::WriteHeader, Error> {
279    decode(bytes)
280}
281
282/// Encode a received row change, execution or dismissal as its D5 frame for
283/// local retention.
284/// Decoding with `WriteFrame::decode` checks it again before it is reapplied.
285pub fn encode_write_frame(value: &crate::dismissal::WriteFrame) -> Result<Vec<u8>, Error> {
286    match value {
287        crate::dismissal::WriteFrame::Change(row) => {
288            crate::encode_frame(crate::kinds::ROW_CHANGE, row)
289        }
290        crate::dismissal::WriteFrame::Execution(execution) => {
291            crate::encode_frame(crate::kinds::ROW_EXECUTION, execution)
292        }
293        crate::dismissal::WriteFrame::Dismissal(dismissal) => {
294            crate::encode_frame(crate::kinds::DISMISSAL, dismissal)
295        }
296    }
297}
298
299#[cfg(test)]
300#[path = "merge_fields_tests.rs"]
301mod tests;