Skip to main content

cp_ast_json/
lib.rs

1//! Lossless JSON serialization for `cp-ast-core` AST documents.
2//!
3//! Provides full-snapshot JSON roundtrip that preserves arena structure,
4//! tombstones, IDs, counters, and ordering through Rust → JS → Rust cycles.
5//!
6//! Use [`serialize_ast`] and [`deserialize_ast`] for complete documents, or
7//! [`serialize_ast_compact`] when byte size matters. Editor integrations can
8//! serialize actions with [`serialize_action`] / [`deserialize_action`] and
9//! serialize UI projections with [`serialize_projection`].
10//!
11//! # Example
12//!
13//! ```
14//! use cp_ast_core::operation::AstEngine;
15//! use cp_ast_json::{deserialize_ast, serialize_ast};
16//!
17//! let engine = AstEngine::new();
18//! let json = serialize_ast(&engine).expect("serialize");
19//! let restored = deserialize_ast(&json).expect("deserialize");
20//!
21//! assert_eq!(restored.structure.root(), engine.structure.root());
22//! ```
23//!
24//! # Schema Notes
25//!
26//! IDs are encoded as decimal strings so JavaScript callers do not lose integer
27//! precision. The top-level JSON document is versioned with
28//! [`dto::CURRENT_SCHEMA_VERSION`].
29
30/// DTO types that define the stable JSON schema.
31pub mod dto;
32/// Error type returned by JSON conversion functions.
33pub mod error;
34mod from_dto;
35mod to_dto;
36
37mod action_dto;
38mod projection_dto;
39/// Compact share-link encoding helpers.
40pub mod share_state;
41
42pub use dto::AstDocumentEnvelope;
43pub use error::ConversionError;
44
45pub use action_dto::{deserialize_action, serialize_action};
46pub use projection_dto::serialize_projection;
47pub use share_state::{decode_share_state_json, deserialize_share_state, encode_share_state_json};
48
49use cp_ast_core::operation::AstEngine;
50
51/// Serialize an `AstEngine` to a JSON string.
52///
53/// Wraps in a versioned envelope with `schema_version`.
54///
55/// # Errors
56/// Returns `ConversionError::Json` if JSON serialization fails.
57pub fn serialize_ast(engine: &AstEngine) -> Result<String, ConversionError> {
58    let envelope = to_dto::engine_to_envelope(engine);
59    serde_json::to_string_pretty(&envelope).map_err(ConversionError::from)
60}
61
62/// Serialize an `AstEngine` to a compact JSON string.
63///
64/// This is intended for transport-oriented use cases such as share links.
65///
66/// # Errors
67/// Returns `ConversionError::Json` if JSON serialization fails.
68pub fn serialize_ast_compact(engine: &AstEngine) -> Result<String, ConversionError> {
69    let envelope = to_dto::engine_to_envelope(engine);
70    serde_json::to_string(&envelope).map_err(ConversionError::from)
71}
72
73/// Deserialize an `AstEngine` from a JSON string.
74///
75/// Validates schema version and arena consistency.
76///
77/// # Errors
78/// Returns `ConversionError` if JSON is invalid, version unsupported,
79/// or arena data is inconsistent.
80pub fn deserialize_ast(json: &str) -> Result<AstEngine, ConversionError> {
81    let envelope: AstDocumentEnvelope = serde_json::from_str(json)?;
82    from_dto::envelope_to_engine(envelope)
83}