Skip to main content

crdt_graph/flatbuffers/
bytes.rs

1use crate::graph::UpdateOperation;
2use crate::types::bytes;
3use flatbuffers::FlatBufferBuilder;
4
5use super::crdt_graph_with_data_generated::crdt_graph::fb_data;
6use super::{uuid_from_fb, DecodeError};
7
8// ---------------------------------------------------------------------------
9// Encoding
10// ---------------------------------------------------------------------------
11
12/// Encodes a single [`bytes::Operation`] into a FlatBuffer byte vector (file identifier `"CRD2"`).
13pub fn encode_operation(op: &bytes::Operation) -> Vec<u8> {
14    let mut builder = FlatBufferBuilder::new();
15    let op_offset = write_update_operation(&mut builder, op);
16
17    let ops_vec = builder.create_vector(&[op_offset]);
18    let log = fb_data::OperationLog::create(
19        &mut builder,
20        &fb_data::OperationLogArgs {
21            operations: Some(ops_vec),
22        },
23    );
24    builder.finish(log, Some("CRD2"));
25    builder.finished_data().to_vec()
26}
27
28/// Encodes multiple operations into a single FlatBuffer byte vector.
29pub fn encode_operation_log(ops: &[bytes::Operation]) -> Vec<u8> {
30    let mut builder = FlatBufferBuilder::new();
31
32    let offsets: Vec<_> = ops
33        .iter()
34        .map(|op| write_update_operation(&mut builder, op))
35        .collect();
36
37    let ops_vec = builder.create_vector(&offsets);
38    let log = fb_data::OperationLog::create(
39        &mut builder,
40        &fb_data::OperationLogArgs {
41            operations: Some(ops_vec),
42        },
43    );
44    builder.finish(log, Some("CRD2"));
45    builder.finished_data().to_vec()
46}
47
48fn write_update_operation<'bldr, A: flatbuffers::Allocator + 'bldr>(
49    builder: &mut FlatBufferBuilder<'bldr, A>,
50    op: &bytes::Operation,
51) -> flatbuffers::WIPOffset<fb_data::UpdateOperation<'bldr>> {
52    match op {
53        UpdateOperation::AddVertex(v) => {
54            let id = fb_data::Uuid(*v.id.as_bytes());
55            let data = v.data.as_ref().map(|d| builder.create_vector(d));
56            let inner = fb_data::AddVertex::create(
57                builder,
58                &fb_data::AddVertexArgs {
59                    id: Some(&id),
60                    data,
61                },
62            );
63            fb_data::UpdateOperation::create(
64                builder,
65                &fb_data::UpdateOperationArgs {
66                    operation_type: fb_data::Operation::AddVertex,
67                    operation: Some(inner.as_union_value()),
68                },
69            )
70        }
71        UpdateOperation::RemoveVertex(v) => {
72            let id = fb_data::Uuid(*v.id.as_bytes());
73            let add_vertex_id = fb_data::Uuid(*v.add_vertex_id.as_bytes());
74            let inner = fb_data::RemoveVertex::create(
75                builder,
76                &fb_data::RemoveVertexArgs {
77                    id: Some(&id),
78                    add_vertex_id: Some(&add_vertex_id),
79                },
80            );
81            fb_data::UpdateOperation::create(
82                builder,
83                &fb_data::UpdateOperationArgs {
84                    operation_type: fb_data::Operation::RemoveVertex,
85                    operation: Some(inner.as_union_value()),
86                },
87            )
88        }
89        UpdateOperation::AddEdge(e) => {
90            let id = fb_data::Uuid(*e.id.as_bytes());
91            let source = fb_data::Uuid(*e.source.as_bytes());
92            let target = fb_data::Uuid(*e.target.as_bytes());
93            let data = e.data.as_ref().map(|d| builder.create_vector(d));
94            let inner = fb_data::AddEdge::create(
95                builder,
96                &fb_data::AddEdgeArgs {
97                    id: Some(&id),
98                    source: Some(&source),
99                    target: Some(&target),
100                    data,
101                },
102            );
103            fb_data::UpdateOperation::create(
104                builder,
105                &fb_data::UpdateOperationArgs {
106                    operation_type: fb_data::Operation::AddEdge,
107                    operation: Some(inner.as_union_value()),
108                },
109            )
110        }
111        UpdateOperation::RemoveEdge(e) => {
112            let id = fb_data::Uuid(*e.id.as_bytes());
113            let add_edge_id = fb_data::Uuid(*e.add_edge_id.as_bytes());
114            let inner = fb_data::RemoveEdge::create(
115                builder,
116                &fb_data::RemoveEdgeArgs {
117                    id: Some(&id),
118                    add_edge_id: Some(&add_edge_id),
119                },
120            );
121            fb_data::UpdateOperation::create(
122                builder,
123                &fb_data::UpdateOperationArgs {
124                    operation_type: fb_data::Operation::RemoveEdge,
125                    operation: Some(inner.as_union_value()),
126                },
127            )
128        }
129    }
130}
131
132// ---------------------------------------------------------------------------
133// Decoding
134// ---------------------------------------------------------------------------
135
136/// Decodes a single operation from a with-data FlatBuffer.
137pub fn decode_operation(buf: &[u8]) -> Result<bytes::Operation, DecodeError> {
138    let ops = decode_operation_log(buf)?;
139    ops.into_iter()
140        .next()
141        .ok_or(DecodeError::UnknownOperationType)
142}
143
144/// Decodes all operations from a with-data FlatBuffer `OperationLog`.
145pub fn decode_operation_log(buf: &[u8]) -> Result<Vec<bytes::Operation>, DecodeError> {
146    let log = fb_data::root_as_operation_log(buf)?;
147    let operations = log.operations();
148
149    let mut result = Vec::with_capacity(operations.len());
150    for fb_op in operations.iter() {
151        let op = read_update_operation(&fb_op)?;
152        result.push(op);
153    }
154    Ok(result)
155}
156
157fn read_update_operation(
158    fb_op: &fb_data::UpdateOperation<'_>,
159) -> Result<bytes::Operation, DecodeError> {
160    match fb_op.operation_type() {
161        fb_data::Operation::AddVertex => {
162            let v = fb_op
163                .operation_as_add_vertex()
164                .ok_or(DecodeError::UnknownOperationType)?;
165            Ok(UpdateOperation::AddVertex(bytes::AddVertex {
166                id: uuid_from_fb(&v.id().0),
167                data: v.data().map(|d| d.bytes().to_vec()),
168            }))
169        }
170        fb_data::Operation::RemoveVertex => {
171            let v = fb_op
172                .operation_as_remove_vertex()
173                .ok_or(DecodeError::UnknownOperationType)?;
174            Ok(UpdateOperation::RemoveVertex(crate::types::RemoveVertex {
175                id: uuid_from_fb(&v.id().0),
176                add_vertex_id: uuid_from_fb(&v.add_vertex_id().0),
177            }))
178        }
179        fb_data::Operation::AddEdge => {
180            let e = fb_op
181                .operation_as_add_edge()
182                .ok_or(DecodeError::UnknownOperationType)?;
183            Ok(UpdateOperation::AddEdge(bytes::AddEdge {
184                id: uuid_from_fb(&e.id().0),
185                source: uuid_from_fb(&e.source().0),
186                target: uuid_from_fb(&e.target().0),
187                data: e.data().map(|d| d.bytes().to_vec()),
188            }))
189        }
190        fb_data::Operation::RemoveEdge => {
191            let e = fb_op
192                .operation_as_remove_edge()
193                .ok_or(DecodeError::UnknownOperationType)?;
194            Ok(UpdateOperation::RemoveEdge(crate::types::RemoveEdge {
195                id: uuid_from_fb(&e.id().0),
196                add_edge_id: uuid_from_fb(&e.add_edge_id().0),
197            }))
198        }
199        _ => Err(DecodeError::UnknownOperationType),
200    }
201}