tensogram_wasm/remote_scan.rs
1// (C) Copyright 2026- ECMWF and individual contributors.
2//
3// This software is licensed under the terms of the Apache Licence Version 2.0
4// which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5// In applying this licence, ECMWF does not waive the privileges and immunities
6// granted to it by virtue of its status as an intergovernmental organisation nor
7// does it submit to any jurisdiction.
8
9//! WASM bindings for the bidirectional remote-scan parsers.
10//!
11//! Four thin wrappers over [`tensogram::remote_scan_parse`] — the
12//! TypeScript walker dispatches on the `{ kind: ..., ... }` JS shape
13//! produced here, mirroring the Rust dispatch table in
14//! `tensogram::remote::apply_round_outcomes`.
15//!
16//! Each export accepts a byte slice plus cursor / size scalars and
17//! returns a serialised outcome object whose shape is pinned by the
18//! `#[serde(tag = "kind", rename_all_fields = "camelCase")]`
19//! attribute on the underlying enum — only field names are
20//! camel-cased; the `"kind"` tag values stay PascalCase. See the
21//! [`tensogram::remote_scan_parse`] module docs for the full
22//! taxonomy.
23
24use crate::convert::to_js;
25use tensogram::{
26 parse_backward_postamble, parse_forward_preamble,
27 same_message_check as core_same_message_check, validate_backward_preamble,
28};
29use wasm_bindgen::prelude::*;
30
31/// Parse a backward-postamble fetch and return its outcome.
32///
33/// @param pa_bytes - The 24-byte postamble at `[snap_prev - 24, snap_prev)`.
34/// @param snap_next - Forward cursor (lower bound of the unknown gap).
35/// @param snap_prev - Backward cursor (upper bound of the unknown gap).
36/// @returns One of:
37/// - `{ kind: "Format", reason: string }`
38/// - `{ kind: "Streaming" }`
39/// - `{ kind: "NeedPreambleValidation", msgStart: bigint, length: bigint, firstFooterOffset: bigint }`
40///
41/// `firstFooterOffset` mirrors the postamble's `first_footer_offset`
42/// field — relative to the candidate message start. Equals
43/// `length - POSTAMBLE_SIZE` when the message has no footer frames,
44/// strictly less when a footer region is present. Dispatchers can
45/// use this with `tensogram::footer_region_present` to decide whether
46/// to fold an eager footer-region fetch into the same paired round
47/// as the candidate-preamble validation; the footer fetch is
48/// best-effort and never poisons preamble validation.
49#[wasm_bindgen]
50pub fn parse_backward_postamble_outcome(
51 pa_bytes: &[u8],
52 snap_next: u64,
53 snap_prev: u64,
54) -> Result<JsValue, JsValue> {
55 to_js(&parse_backward_postamble(pa_bytes, snap_next, snap_prev))
56}
57
58/// Validate a backward candidate preamble and return the commit decision.
59///
60/// @param preamble_bytes - The 24-byte preamble at `[msg_start, msg_start+24)`.
61/// @param msg_start - Candidate message-start offset from
62/// [`parse_backward_postamble_outcome`].
63/// @param length - Postamble's claimed `total_length`.
64/// @returns One of:
65/// - `{ kind: "Format", reason: string }`
66/// - `{ kind: "Layout", offset: bigint, length: bigint }`
67#[wasm_bindgen]
68pub fn validate_backward_preamble_outcome(
69 preamble_bytes: &[u8],
70 msg_start: u64,
71 length: u64,
72) -> Result<JsValue, JsValue> {
73 to_js(&validate_backward_preamble(preamble_bytes, msg_start, length))
74}
75
76/// Parse a forward-preamble fetch and return its outcome.
77///
78/// @param preamble_bytes - The 24-byte preamble at `[pos, pos+24)`.
79/// @param pos - Absolute byte offset where the preamble begins.
80/// @param file_size - Total file size.
81/// @param bound - Soft upper bound (`prev_scan_offset` in
82/// bidirectional mode, `file_size` in forward-only mode).
83/// @returns One of:
84/// - `{ kind: "Hit", offset: bigint, length: bigint, msgEnd: bigint }`
85/// - `{ kind: "HitBeyondBound", offset: bigint, length: bigint, msgEnd: bigint }`
86/// - `{ kind: "Streaming", remaining: bigint }`
87/// - `{ kind: "Terminate", reason: string }`
88#[wasm_bindgen]
89pub fn parse_forward_preamble_outcome(
90 preamble_bytes: &[u8],
91 pos: u64,
92 file_size: u64,
93 bound: u64,
94) -> Result<JsValue, JsValue> {
95 to_js(&parse_forward_preamble(preamble_bytes, pos, file_size, bound))
96}
97
98/// `true` iff a forward `Hit` and a backward-validated layout
99/// describe the same message — used by the dispatch table to detect
100/// the 1-message file and odd-count meet-in-the-middle cases.
101#[wasm_bindgen]
102pub fn same_message_check(
103 fwd_offset: u64,
104 fwd_length: u64,
105 layout_offset: u64,
106 layout_length: u64,
107) -> bool {
108 core_same_message_check(fwd_offset, fwd_length, layout_offset, layout_length)
109}