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
//! The standard `serde`/pbjson JSON encoding used by Rust stores `google.protobuf.Any`
//! fields as `{"typeUrl": "...", "value": "<base64>"}`. Go's `protojson` library uses a
//! different encoding: `{"@type": "...", "field1": val, ...}` where the concrete message's
//! fields are inlined. `serde_json::from_str::<Plan>` fails on Go-produced JSON because it
//! only understands the `typeUrl/value` form.
//!
//! [`prost_reflect::DynamicMessage`] implements the full protobuf JSON mapping spec and
//! handles both forms, as long as the `DescriptorPool` contains the schema for every type
//! URL referenced in the JSON.
//!
//! This module exposes [`build_descriptor_pool`] (to construct
//! the pool, optionally merging in extra descriptor blobs for extension types) and
//! [`parse_json`] (to parse a JSON string into a [`Plan`] using the pool).
//!
//! # Example
//!
//! ```rust,ignore
//! use substrait_explain::json::{build_descriptor_pool, parse_json};
//!
//! static MY_EXT: &[u8] = include_bytes!("my_extensions.bin");
//! let pool = build_descriptor_pool(&[MY_EXT]).unwrap();
//! // Works with both Go protojson and Rust pbjson encoding.
//! let plan = parse_json(json_str, &pool).unwrap();
//! ```
use Context;
use Message;
use ;
use FileDescriptorSet;
use Plan;
/// Build a [`DescriptorPool`] covering the Substrait core schema plus any extra
/// descriptor passed in.
/// - **Naive** (`{"typeUrl": "...", "value": "<base64>"}`): decoded via
/// `serde_json` and `pbjson`.
/// - This takes the protobuf fields of an `Any` (`type_url`, `value`) and
/// serializes them like it would any other field. This is the 'naive'
/// approach to JSON encoding protobufs; see
/// <https://github.com/influxdata/pbjson/issues/2>
/// - **Standard** (`{"@type": "...", "field": value, ...}`): decoded via
/// `prost-reflect`
/// - `Any` is a Well-Known Type in Protobuf, so in the standard, it has
/// special handling: the protobuf `type_url` should become the JSON `@type`
/// field, and other fields should be inlined. See
/// <https://protobuf.dev/reference/protobuf/google.protobuf/#any>.
/// - This requires the concrete type's schema to be present in `pool`.
///
/// The naive method is tried first (via `serde_json` + `pbjson`); we fall back
/// to `prost-reflect`, which requires descriptors but can decode
/// standards-correct JSON-encoded protobufs.