1use flatbuffers::{FlatBufferBuilder, WIPOffset};
2
3use crate::{ThreadEdge, ThreadPointer, ThreadingSnapshot, TimelineBlock};
4
5use super::fb;
6use super::THREADING_GRAPH_SCHEMA_VERSION;
7
8#[must_use]
9pub fn encode_threading_snapshot(snapshot: &ThreadingSnapshot) -> Vec<u8> {
10 let mut builder = FlatBufferBuilder::new();
11
12 let edges: Vec<WIPOffset<fb::ThreadEdge<'_>>> = snapshot
13 .edges
14 .iter()
15 .map(|edge| encode_edge(&mut builder, edge))
16 .collect();
17 let edges = builder.create_vector(&edges);
18
19 let blocks: Vec<WIPOffset<fb::TimelineBlockEntry<'_>>> = snapshot
20 .blocks
21 .iter()
22 .map(|block| encode_block(&mut builder, block))
23 .collect();
24 let blocks = builder.create_vector(&blocks);
25
26 let pending: Vec<WIPOffset<fb::BlockEventId<'_>>> = snapshot
27 .pending_ancestor_ids
28 .iter()
29 .map(|id| encode_id(&mut builder, id))
30 .collect();
31 let pending = builder.create_vector(&pending);
32
33 let root = fb::ThreadingSnapshot::create(
34 &mut builder,
35 &fb::ThreadingSnapshotArgs {
36 schema_version: THREADING_GRAPH_SCHEMA_VERSION,
37 edges: Some(edges),
38 blocks: Some(blocks),
39 pending_ancestor_ids: Some(pending),
40 },
41 );
42 fb::finish_threading_snapshot_buffer(&mut builder, root);
43 builder.finished_data().to_vec()
44}
45
46fn encode_edge<'bldr>(
47 builder: &mut FlatBufferBuilder<'bldr>,
48 edge: &ThreadEdge,
49) -> WIPOffset<fb::ThreadEdge<'bldr>> {
50 let event_id = builder.create_string(&edge.event_id);
51 let author_pubkey = builder.create_string(&edge.author_pubkey);
52 let parent = edge.parent.as_ref().map(|p| encode_pointer(builder, p));
53 let root = edge.root.as_ref().map(|p| encode_pointer(builder, p));
54 let parent_author_pubkey = edge
55 .parent_author_pubkey
56 .as_ref()
57 .map(|p| builder.create_string(p));
58 fb::ThreadEdge::create(
59 builder,
60 &fb::ThreadEdgeArgs {
61 event_id: Some(event_id),
62 author_pubkey: Some(author_pubkey),
63 kind: edge.kind,
64 created_at: edge.created_at,
65 parent,
66 root,
67 parent_author_pubkey,
68 },
69 )
70}
71
72fn encode_block<'bldr>(
73 builder: &mut FlatBufferBuilder<'bldr>,
74 block: &TimelineBlock,
75) -> WIPOffset<fb::TimelineBlockEntry<'bldr>> {
76 match block {
77 TimelineBlock::Standalone { id, root } => {
78 let standalone_id = builder.create_string(id);
79 let standalone_root = root.as_ref().map(|p| encode_pointer(builder, p));
80 fb::TimelineBlockEntry::create(
81 builder,
82 &fb::TimelineBlockEntryArgs {
83 kind: fb::TimelineBlockKind::Standalone,
84 standalone_id: Some(standalone_id),
85 standalone_root,
86 module_event_ids: None,
87 module_has_gap: false,
88 module_root: None,
89 },
90 )
91 }
92 TimelineBlock::Module {
93 events,
94 has_gap,
95 root,
96 } => {
97 let ids: Vec<WIPOffset<fb::BlockEventId<'_>>> =
98 events.iter().map(|id| encode_id(builder, id)).collect();
99 let module_event_ids = builder.create_vector(&ids);
100 let module_root = root.as_ref().map(|p| encode_pointer(builder, p));
101 fb::TimelineBlockEntry::create(
102 builder,
103 &fb::TimelineBlockEntryArgs {
104 kind: fb::TimelineBlockKind::Module,
105 standalone_id: None,
106 standalone_root: None,
107 module_event_ids: Some(module_event_ids),
108 module_has_gap: *has_gap,
109 module_root,
110 },
111 )
112 }
113 }
114}
115
116fn encode_pointer<'bldr>(
117 builder: &mut FlatBufferBuilder<'bldr>,
118 pointer: &ThreadPointer,
119) -> WIPOffset<fb::ThreadPointer<'bldr>> {
120 match pointer {
121 ThreadPointer::Event { id, relay, kind } => {
122 let id = builder.create_string(id);
123 let relay = relay.as_ref().map(|r| builder.create_string(r));
124 fb::ThreadPointer::create(
125 builder,
126 &fb::ThreadPointerArgs {
127 kind: fb::ThreadPointerKind::Event,
128 id: Some(id),
129 coord: None,
130 uri: None,
131 relay,
132 has_kind_num: kind.is_some(),
133 kind_num: kind.unwrap_or_default(),
134 },
135 )
136 }
137 ThreadPointer::Address { coord, relay, kind } => {
138 let coord = builder.create_string(coord);
139 let relay = relay.as_ref().map(|r| builder.create_string(r));
140 fb::ThreadPointer::create(
141 builder,
142 &fb::ThreadPointerArgs {
143 kind: fb::ThreadPointerKind::Address,
144 id: None,
145 coord: Some(coord),
146 uri: None,
147 relay,
148 has_kind_num: kind.is_some(),
149 kind_num: kind.unwrap_or_default(),
150 },
151 )
152 }
153 ThreadPointer::External { uri } => {
154 let uri = builder.create_string(uri);
155 fb::ThreadPointer::create(
156 builder,
157 &fb::ThreadPointerArgs {
158 kind: fb::ThreadPointerKind::External,
159 id: None,
160 coord: None,
161 uri: Some(uri),
162 relay: None,
163 has_kind_num: false,
164 kind_num: 0,
165 },
166 )
167 }
168 }
169}
170
171fn encode_id<'bldr>(
172 builder: &mut FlatBufferBuilder<'bldr>,
173 id: &str,
174) -> WIPOffset<fb::BlockEventId<'bldr>> {
175 let id = builder.create_string(id);
176 fb::BlockEventId::create(builder, &fb::BlockEventIdArgs { id: Some(id) })
177}