Skip to main content

luaur_analysis/methods/
object_emitter_write_pair.rs

1//! Source: `Analysis/include/Luau/JsonEmitter.h` (lines 155-167, hand-ported)
2//!
3//! C++ template:
4//! ```cpp
5//! template<typename T>
6//! void writePair(std::string_view name, T value)
7//! {
8//!     if (finished) return;
9//!     emitter->writeComma();
10//!     write(*emitter, name);
11//!     emitter->writeRaw(':');
12//!     write(*emitter, value);
13//! }
14//! ```
15//!
16//! C++ resolves the two `write(*emitter, ...)` calls by overload resolution over
17//! the `write(JsonEmitter&, T)` family. Rust expresses that overload set as the
18//! `WriteJson` trait defined here: every value that can be a JSON value impls it
19//! by delegating to the corresponding `write_json_emitter_*` free function (the
20//! ported C++ `write` overloads). The concrete `impl WriteJson for <T>` blocks
21//! are colocated with the function that ports the matching overload:
22//!   - scalars / strings / pointers          -> this file
23//!   - `Vec<T>`                               -> functions/write_json_emitter.rs
24//!   - `Option<T>`                            -> functions/write_json_emitter_alt_b.rs
25//!   - `unordered_map<String, T>` / hash maps -> functions/write_json_emitter_alt_c.rs
26
27extern crate alloc;
28
29use crate::functions::write_dcr_logger::write_json_emitter_t;
30use crate::functions::write_json_emitter_alt_ae::write_json_emitter_string_view;
31use crate::functions::write_json_emitter_alt_w::write_json_emitter_bool;
32use crate::functions::write_json_emitter_alt_x::write_json_emitter_f64;
33use crate::records::json_emitter::JsonEmitter;
34use crate::records::object_emitter::ObjectEmitter;
35use alloc::string::String;
36use alloc::string::ToString;
37
38/// Rust shape of the overloaded `void write(JsonEmitter&, T)` family. A type
39/// implements this iff there is a `write(JsonEmitter&, T)` overload for it in
40/// C++. The single method writes the JSON encoding of `self` into `emitter`.
41pub trait WriteJson {
42    fn write_json(&self, emitter: &mut JsonEmitter);
43}
44
45/// `write(*emitter, value)` where `value` was bound to a reference at the call
46/// site (`writePair("k", &field)`); forward through the reference.
47impl<T: WriteJson + ?Sized> WriteJson for &T {
48    fn write_json(&self, emitter: &mut JsonEmitter) {
49        (**self).write_json(emitter);
50    }
51}
52
53// --- scalar overloads (write(JsonEmitter&, bool/double/int...)) ---
54
55impl WriteJson for bool {
56    fn write_json(&self, emitter: &mut JsonEmitter) {
57        write_json_emitter_bool(emitter, *self);
58    }
59}
60
61impl WriteJson for f64 {
62    fn write_json(&self, emitter: &mut JsonEmitter) {
63        write_json_emitter_f64(emitter, *self);
64    }
65}
66
67macro_rules! write_json_int {
68    ($($t:ty),*) => {$(
69        impl WriteJson for $t {
70            fn write_json(&self, emitter: &mut JsonEmitter) {
71                emitter.write_raw_string_view(&self.to_string());
72            }
73        }
74    )*};
75}
76// NB: no i8/u8 — C++ `char` writes as a one-char STRING, not a JSON integer.
77write_json_int!(i32, u32, i64, u64, usize, isize, i16, u16);
78
79// --- string overloads (write(JsonEmitter&, std::string_view / std::string)) ---
80
81impl WriteJson for str {
82    fn write_json(&self, emitter: &mut JsonEmitter) {
83        write_json_emitter_string_view(emitter, self);
84    }
85}
86
87impl WriteJson for String {
88    fn write_json(&self, emitter: &mut JsonEmitter) {
89        write_json_emitter_string_view(emitter, self.as_str());
90    }
91}
92
93// --- pointer overload (write(JsonEmitter&, const T*) via to_pointer_id) ---
94// In DcrLogger, raw pointers are written through `write_json_emitter_t`, which
95// emits the pointer id. Matches `writePair("currentConstraint", snapshot.ptr)`.
96
97impl<T> WriteJson for *const T {
98    fn write_json(&self, emitter: &mut JsonEmitter) {
99        write_json_emitter_t(emitter, *self);
100    }
101}
102
103impl ObjectEmitter {
104    /// `writePair(std::string_view name, T value)`
105    pub fn write_pair<T: WriteJson>(&mut self, name: &str, value: T) {
106        if self.finished {
107            return;
108        }
109
110        let emitter = unsafe { &mut *self.emitter };
111        emitter.write_comma();
112        // write(*emitter, name) — `name` is a std::string_view => the string overload.
113        write_json_emitter_string_view(emitter, name);
114        emitter.write_raw_c_char(b':' as core::ffi::c_char);
115        // write(*emitter, value)
116        value.write_json(emitter);
117    }
118}
119
120// --- record overloads (the DcrLogger `write(JsonEmitter&, const X&)` family) ---
121// Each delegates to its ported free function; these are the `write` overloads
122// that let snapshot/log records be JSON values via writePair/writeValue.
123macro_rules! write_json_via {
124    ($ty:path => $func:path) => {
125        impl WriteJson for $ty {
126            fn write_json(&self, emitter: &mut JsonEmitter) {
127                $func(emitter, self);
128            }
129        }
130    };
131}
132
133write_json_via!(luaur_ast::records::location::Location
134    => crate::functions::write_dcr_logger_alt_f::write_json_emitter_location);
135write_json_via!(crate::records::error_snapshot::ErrorSnapshot
136    => crate::functions::write_dcr_logger_alt_g::write_json_emitter_error_snapshot);
137write_json_via!(crate::records::binding_snapshot::BindingSnapshot
138    => crate::functions::write_dcr_logger_alt_h::write_json_emitter_binding_snapshot);
139write_json_via!(crate::records::type_binding_snapshot::TypeBindingSnapshot
140    => crate::functions::write_dcr_logger_alt_i::write_json_emitter_type_binding_snapshot);
141write_json_via!(crate::records::expr_types_at_location::ExprTypesAtLocation
142    => crate::functions::write_dcr_logger_alt_k::write_json_emitter_expr_types_at_location);
143write_json_via!(crate::records::annotation_types_at_location::AnnotationTypesAtLocation
144    => crate::functions::write_dcr_logger_alt_l::write_json_emitter_annotation_types_at_location);
145write_json_via!(crate::records::constraint_generation_log::ConstraintGenerationLog
146    => crate::functions::write_dcr_logger_alt_m::write_json_emitter_constraint_generation_log);
147write_json_via!(crate::records::scope_snapshot::ScopeSnapshot
148    => crate::functions::write_dcr_logger_alt_n::write_json_emitter_scope_snapshot);
149write_json_via!(crate::records::constraint_block::ConstraintBlock
150    => crate::functions::write_dcr_logger_alt_o::write_json_emitter_constraint_block);
151write_json_via!(crate::records::constraint_snapshot::ConstraintSnapshot
152    => crate::functions::write_dcr_logger_alt_p::write_json_emitter_constraint_snapshot);
153write_json_via!(crate::records::boundary_snapshot::BoundarySnapshot
154    => crate::functions::write_dcr_logger_alt_q::write_json_emitter_boundary_snapshot);
155write_json_via!(crate::type_aliases::step_snapshot::StepSnapshot
156    => crate::functions::write_dcr_logger_alt_t::write_json_emitter_step_snapshot);
157write_json_via!(crate::records::type_solve_log::TypeSolveLog
158    => crate::functions::write_dcr_logger_alt_u::write_json_emitter_type_solve_log);
159write_json_via!(crate::records::type_check_log::TypeCheckLog
160    => crate::functions::write_dcr_logger_alt_v::write_json_emitter_type_check_log);