Skip to main content

crdt_graph/flatbuffers/
simple.rs

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