1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! The one place Rust says that a scan refused a record (issue #3395).
//!
//! [`EntityScanner`](super::EntityScanner) drops a record whose instance name
//! does not fit `u32` and counts it in
//! [`skipped_oversized_ids`](super::EntityScanner::skipped_oversized_ids).
//! Dropping it is the only outcome the workspace's `u32` express-id columns
//! can hold, but a load that comes back quietly short reads exactly like a
//! load that had nothing to drop — so the counter is only half a guard. This
//! module is the other half.
//!
//! It is one home, not one call site: the scanner has ~50 consumers and the
//! first version of #3395 wired the report into exactly one of them, which is
//! the defect two reviewers found. Every consumer that builds a model or an
//! entity index from a scan calls [`report_oversized_ids`] once, and the
//! message itself is written here so the wording cannot drift the way four
//! copies of it would.
//!
//! **A refusal is a diagnostic, not an error.** `#4294967297` is a legal ISO
//! 10303-21 instance name, so a file carrying one is not corrupt — ifc-lite
//! simply cannot represent that one record. Failing the load would turn a
//! one-record loss into a total loss on a file that is otherwise fine, and it
//! would make native refuse a file the browser still opens (the wasm entry
//! points warn and keep going). So: report on every path, loudly, and keep
//! loading.
//!
//! ## Where the message goes
//!
//! Native builds write to stderr, which is where the CLI, the server and the
//! PyO3 wheel already surface their warnings. `wasm32-unknown-unknown` has no
//! stderr — `eprintln!` there is a silent no-op, which is the same
//! absence-reads-as-success failure one layer down — so the wasm bindings
//! install a console sink through [`set_report_sink`] from
//! `#[wasm_bindgen(start)] init()`, i.e. when the module LOADS, not when an
//! `IfcAPI` is constructed: the free functions and `ColumnarEntityIndex`
//! report too, and a load that never constructs an `IfcAPI` would otherwise
//! scan with the sink still unset. Anything embedding this crate with its own
//! log pipeline can do the same.
use REPORT_SINK;
/// Route every scan diagnostic in this crate — [`report_oversized_ids`] and
/// [`super::malformed_records::report_malformed_records`] alike — to `sink`
/// instead of stderr.
///
/// Returns `true` when this call installed the sink, `false` when one was
/// already installed (the first wins). Callers on `wasm32` MUST install one:
/// the default sink is `eprintln!`, which that target discards.
/// The one-line report for `skipped` refused records, or `None` when the scan
/// refused nothing.
///
/// Exposed separately from [`report_oversized_ids`] so a host that already has
/// a place to put the text — the wasm bindings put it on the browser console,
/// and carry the number itself across to the JS entity-index handoff — emits
/// the same sentence rather than writing a second one.
/// Emit [`oversized_id_report`] to the installed sink (stderr by default).
///
/// A no-op at `skipped == 0`, so a caller can hand it
/// `scanner.skipped_oversized_ids()` unconditionally.