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}