ifc_lite_server/routes/parse/stream_event.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! The SSE wire type of `POST /api/v1/parse/parquet-stream`.
6//!
7//! Its own module because it has two producers that must not drift: the live
8//! parse in `parquet_stream.rs` and the cache replay in `cached_replay.rs`,
9//! whose whole contract is that a hit is indistinguishable from a miss.
10
11use crate::types::{ModelMetadata, ProcessingStats};
12use ifc_lite_processing::SymbolicDataWithProvenance;
13use serde::Serialize;
14
15/// SSE event types for Parquet streaming.
16// Variant sizes differ because the payload events carry buffers; boxing them
17// would complicate the SSE serialization path for no runtime benefit here.
18#[allow(clippy::large_enum_variant)]
19#[derive(Debug, Clone, Serialize)]
20#[serde(tag = "type", rename_all = "lowercase")]
21pub enum ParquetStreamEvent {
22 /// Initial event with estimated totals.
23 Start {
24 total_estimate: usize,
25 cache_key: String,
26 },
27 /// Progress update.
28 Progress { processed: usize, total: usize },
29 /// Batch of geometry data as base64-encoded Parquet.
30 Batch {
31 /// Base64-encoded Parquet data containing this batch's meshes.
32 data: String,
33 /// Number of meshes in this batch.
34 mesh_count: usize,
35 /// Batch sequence number (1-indexed).
36 batch_number: usize,
37 /// Cross-batch streams only (`stream_shapes=cross-batch`, #5407):
38 /// the whole-stream index of this batch's first vertex row. The mesh
39 /// rows' `vertex_start` is whole-stream too and may point below it,
40 /// at a shape an earlier batch carried. ABSENT on every batch-local
41 /// stream, which is how a client learns the server did not honour the
42 /// opt-in and each batch decodes on its own.
43 #[serde(skip_serializing_if = "Option::is_none")]
44 vertex_base: Option<u32>,
45 /// Companion of `vertex_base`, in indices (the unit of `index_start`),
46 /// not index-table rows.
47 #[serde(skip_serializing_if = "Option::is_none")]
48 index_base: Option<u32>,
49 },
50 /// Processing complete.
51 Complete {
52 stats: ProcessingStats,
53 metadata: ModelMetadata,
54 /// 2D symbol data extracted from `IfcAnnotation` and `IfcGrid`
55 /// entities — parity with `POST /api/v1/parse` (issue #900).
56 #[serde(default, skip_serializing_if = "SymbolicDataWithProvenance::is_empty")]
57 symbolic_data: SymbolicDataWithProvenance,
58 },
59 /// Error occurred.
60 Error { message: String },
61}