use flatbuffers::{FlatBufferBuilder, WIPOffset};
use crate::{ThreadEdge, ThreadPointer, ThreadingSnapshot, TimelineBlock};
use super::fb;
use super::THREADING_GRAPH_SCHEMA_VERSION;
#[must_use]
pub fn encode_threading_snapshot(snapshot: &ThreadingSnapshot) -> Vec<u8> {
let mut builder = FlatBufferBuilder::new();
let edges: Vec<WIPOffset<fb::ThreadEdge<'_>>> = snapshot
.edges
.iter()
.map(|edge| encode_edge(&mut builder, edge))
.collect();
let edges = builder.create_vector(&edges);
let blocks: Vec<WIPOffset<fb::TimelineBlockEntry<'_>>> = snapshot
.blocks
.iter()
.map(|block| encode_block(&mut builder, block))
.collect();
let blocks = builder.create_vector(&blocks);
let pending: Vec<WIPOffset<fb::BlockEventId<'_>>> = snapshot
.pending_ancestor_ids
.iter()
.map(|id| encode_id(&mut builder, id))
.collect();
let pending = builder.create_vector(&pending);
let root = fb::ThreadingSnapshot::create(
&mut builder,
&fb::ThreadingSnapshotArgs {
schema_version: THREADING_GRAPH_SCHEMA_VERSION,
edges: Some(edges),
blocks: Some(blocks),
pending_ancestor_ids: Some(pending),
},
);
fb::finish_threading_snapshot_buffer(&mut builder, root);
builder.finished_data().to_vec()
}
fn encode_edge<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
edge: &ThreadEdge,
) -> WIPOffset<fb::ThreadEdge<'bldr>> {
let event_id = builder.create_string(&edge.event_id);
let author_pubkey = builder.create_string(&edge.author_pubkey);
let parent = edge.parent.as_ref().map(|p| encode_pointer(builder, p));
let root = edge.root.as_ref().map(|p| encode_pointer(builder, p));
let parent_author_pubkey = edge
.parent_author_pubkey
.as_ref()
.map(|p| builder.create_string(p));
fb::ThreadEdge::create(
builder,
&fb::ThreadEdgeArgs {
event_id: Some(event_id),
author_pubkey: Some(author_pubkey),
kind: edge.kind,
created_at: edge.created_at,
parent,
root,
parent_author_pubkey,
},
)
}
fn encode_block<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
block: &TimelineBlock,
) -> WIPOffset<fb::TimelineBlockEntry<'bldr>> {
match block {
TimelineBlock::Standalone { id, root } => {
let standalone_id = builder.create_string(id);
let standalone_root = root.as_ref().map(|p| encode_pointer(builder, p));
fb::TimelineBlockEntry::create(
builder,
&fb::TimelineBlockEntryArgs {
kind: fb::TimelineBlockKind::Standalone,
standalone_id: Some(standalone_id),
standalone_root,
module_event_ids: None,
module_has_gap: false,
module_root: None,
},
)
}
TimelineBlock::Module {
events,
has_gap,
root,
} => {
let ids: Vec<WIPOffset<fb::BlockEventId<'_>>> =
events.iter().map(|id| encode_id(builder, id)).collect();
let module_event_ids = builder.create_vector(&ids);
let module_root = root.as_ref().map(|p| encode_pointer(builder, p));
fb::TimelineBlockEntry::create(
builder,
&fb::TimelineBlockEntryArgs {
kind: fb::TimelineBlockKind::Module,
standalone_id: None,
standalone_root: None,
module_event_ids: Some(module_event_ids),
module_has_gap: *has_gap,
module_root,
},
)
}
}
}
fn encode_pointer<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
pointer: &ThreadPointer,
) -> WIPOffset<fb::ThreadPointer<'bldr>> {
match pointer {
ThreadPointer::Event { id, relay, kind } => {
let id = builder.create_string(id);
let relay = relay.as_ref().map(|r| builder.create_string(r));
fb::ThreadPointer::create(
builder,
&fb::ThreadPointerArgs {
kind: fb::ThreadPointerKind::Event,
id: Some(id),
coord: None,
uri: None,
relay,
has_kind_num: kind.is_some(),
kind_num: kind.unwrap_or_default(),
},
)
}
ThreadPointer::Address { coord, relay, kind } => {
let coord = builder.create_string(coord);
let relay = relay.as_ref().map(|r| builder.create_string(r));
fb::ThreadPointer::create(
builder,
&fb::ThreadPointerArgs {
kind: fb::ThreadPointerKind::Address,
id: None,
coord: Some(coord),
uri: None,
relay,
has_kind_num: kind.is_some(),
kind_num: kind.unwrap_or_default(),
},
)
}
ThreadPointer::External { uri } => {
let uri = builder.create_string(uri);
fb::ThreadPointer::create(
builder,
&fb::ThreadPointerArgs {
kind: fb::ThreadPointerKind::External,
id: None,
coord: None,
uri: Some(uri),
relay: None,
has_kind_num: false,
kind_num: 0,
},
)
}
}
}
fn encode_id<'bldr>(
builder: &mut FlatBufferBuilder<'bldr>,
id: &str,
) -> WIPOffset<fb::BlockEventId<'bldr>> {
let id = builder.create_string(id);
fb::BlockEventId::create(builder, &fb::BlockEventIdArgs { id: Some(id) })
}