sppparse/
lib.rs

1//! Provides a high level way of lazily dereferencing JSON Pointer in [serde](serde) [`Value`](serde_json::Value).
2//!
3//! It can operate in-memory or on files (`JSON` or `YAML`).
4//!
5//! To deserialize an object of type `T` or a pointer to
6//! local or distant document referencing an object of type `T`,
7//! we use the type [SparseSelector](crate::SparseSelector).
8//!
9//! The root document is wrapped in a [SparseRoot](crate::SparseRoot).
10//! This allow a coordination of the state and the cached values.
11//!
12//! Let's take the following `JSON` document :
13//! ```json
14//! {
15//!     "hello": "world",
16//!     "obj": {
17//!         "key1": {
18//!             "$ref": "#/hello"
19//!         },
20//!         "key2": "universe"
21//!     }
22//! }
23//! ```
24//!
25//! Now, let's parse it using the [SparseSelector](crate::SparseSelector) and the [SparseRoot](crate::SparseRoot) :
26//!
27//! ```rust
28//! extern crate sppparse;
29//!
30//! use serde::{Deserialize, Serialize};
31//! use sppparse::{Sparsable, SparsePointer, SparseRoot, SparseSelector};
32//! use std::collections::HashMap;
33//! use std::path::PathBuf;
34//!
35//! #[derive(Debug, Deserialize, Serialize, Sparsable)]
36//! struct ObjectExampleParsed {
37//!     hello: String,
38//!     obj: HashMap<String, SparseSelector<String>>,
39//! }
40//!
41//! fn main() {
42//!     let doc: SparseRoot<ObjectExampleParsed> = SparseRoot::new_from_file(PathBuf::from(concat!(
43//!         env!("CARGO_MANIFEST_DIR"),
44//!         "/",
45//!         "./examples/read_multi_files.json"
46//!     )))
47//!     .unwrap();
48//!     println!("Full object {:#?}", doc.root_get().unwrap());
49//!     println!(
50//!         "A single ref {:#?}",
51//!         doc.root_get().unwrap().obj.get("key1").unwrap().get()
52//!     );
53//!     println!(
54//!         "A single ref {:#?}",
55//!         doc.root_get().unwrap().obj.get("key2").unwrap().get()
56//!     );
57//! }
58//! ```
59//! ## In-memory
60//!
61//! Let's take the following `JSON` example document:
62//!
63//! ```json
64//! {
65//!   "hello": "world",
66//!     "obj": {
67//!       "key1":
68//!       {
69//!         "$ref": "#/hello"
70//!       }
71//!     }
72//! }
73//! ```
74//!
75//! We can just pass [Value](serde_json::Value) or objects that implements [Serialize](serde::Serialize) to the [SparseRoot](crate::SparseRoot)
76//!
77//! ```rust
78//! extern crate sppparse;
79//!
80//! use serde::{Deserialize, Serialize};
81//! use serde_json::json;
82//! use sppparse::{Sparsable, SparsePointer, SparseRoot, SparseSelector};
83//! use std::collections::HashMap;
84//! use std::path::PathBuf;
85//!
86//! #[derive(Debug, Deserialize, Serialize, Sparsable)]
87//! struct ObjectExampleParsed {
88//!     hello: String,
89//!     obj: HashMap<String, SparseSelector<String>>,
90//! }
91//!
92//! fn main() {
93//!     let json_value = json!({
94//!         "hello": "world",
95//!         "obj": {
96//!             "key1": {
97//!                 "$ref": "#/hello"
98//!             }
99//!         }
100//!     });
101//!     let parsed_obj: SparseRoot<ObjectExampleParsed> =
102//!         SparseRoot::new_from_value(json_value, PathBuf::from("hello.json"), vec![]).unwrap();
103//!
104//!     println!(
105//!         "{}",
106//!         parsed_obj
107//!             .root_get()
108//!             .unwrap()
109//!             .obj
110//!             .get("key1")
111//!             .unwrap()
112//!             .get()
113//!             .expect("the dereferenced pointer")
114//!     );
115//! }
116//! ```
117//! ## File backed
118//!
119//! If we take the same object as the in-memory example, but reading from a file,
120//! the rust code would like the following :
121//!
122//! ```rust
123//! extern crate sppparse;
124//!
125//! use serde::{Deserialize, Serialize};
126//! use sppparse::{Sparsable, SparsePointer, SparseRoot, SparseSelector};
127//! use std::collections::HashMap;
128//! use std::path::PathBuf;
129//!
130//! #[derive(Debug, Deserialize, Serialize, Sparsable)]
131//! struct ObjectExampleParsed {
132//!     hello: String,
133//!     obj: HashMap<String, SparseSelector<String>>,
134//! }
135//!
136//! fn main() {
137//!     let val: SparseRoot<ObjectExampleParsed> = SparseRoot::new_from_file(PathBuf::from(concat!(
138//!         env!("CARGO_MANIFEST_DIR"),
139//!         "/",
140//!         "./examples/read_single_file.json"
141//!     )))
142//!     .unwrap();
143//!
144//!     println!(
145//!         "{}",
146//!         val.root_get()
147//!             .unwrap()
148//!             .obj
149//!             .get("key1")
150//!             .unwrap()
151//!             .get()
152//!             .expect("the dereferenced pointer")
153//!     );
154//! }
155//! ```
156//!
157//! ## Updates
158//!
159//! Using [Sparse](crate), it's also possible to modify the parsed value and then save them to disk.
160//!
161//! See the following example :
162//!
163//! ```rust
164//! extern crate sppparse;
165//! use serde::{Deserialize, Serialize};
166//! use sppparse::{Sparsable, SparsePointer, SparseRoot, SparseSelector};
167//! use std::collections::HashMap;
168//! use std::path::PathBuf;
169//!
170//! #[derive(Debug, Deserialize, Serialize, Sparsable)]
171//! struct ObjectExampleParsed {    
172//!     hello: String,
173//!     obj: HashMap<String, SparseSelector<String>>,
174//! }
175//!
176//! fn main() {
177//!     let mut val: SparseRoot<ObjectExampleParsed> = SparseRoot::new_from_file(PathBuf::from(concat!(
178//!         env!("CARGO_MANIFEST_DIR"),
179//!         "/",
180//!         "./examples/read_single_file.json"
181//!     )))
182//!     .unwrap();
183//!
184//!     println!(
185//!         "Before : {}",
186//!         val.root_get()
187//!             .unwrap()
188//!             .obj
189//!             .get("key1")
190//!             .unwrap()
191//!             .get()
192//!             .expect("the dereferenced pointer")
193//!     );
194//!     {
195//!         let state = val.state().clone();
196//!         let mut root_mut = val.root_get_mut().unwrap();
197//!
198//!         let key1 = root_mut.obj.get_mut("key1").unwrap();
199//!         let mut key1_deref = key1.get_mut(state).unwrap();
200//!
201//!         *key1_deref = "universe".to_string();
202//!         key1_deref.sparse_save().unwrap();
203//!         val.sparse_updt().unwrap();
204//!     }
205//!     println!(
206//!         "After : {}",
207//!         val.root_get()
208//!             .unwrap()
209//!             .obj
210//!             .get("key1")
211//!             .unwrap()
212//!             .get()
213//!             .expect("the dereferenced pointer")
214//!     );
215//!     // To persist those modification to disk use :
216//!     //
217//!     // val.save_to_disk(None).unwrap()
218//! }
219//! ```
220#![warn(clippy::all)]
221
222mod sparsable;
223mod sparse_errors;
224mod sparse_metadata;
225mod sparse_pointed_value;
226mod sparse_pointer;
227mod sparse_ref;
228mod sparse_ref_raw;
229mod sparse_ref_raw_inline;
230mod sparse_root;
231mod sparse_selector;
232mod sparse_state;
233mod sparse_value;
234mod sparse_value_mut;
235
236/// The max stack frames [Sparse](crate) will go before returning a [cyclic](crate::SparseError::CyclicRef).
237///
238/// For each [SparseSelector](crate::SparseSelector) in your objects, you should count 3 stack frames.
239///
240/// i.e. If you have a document with a depth of 30 references. The maximum depth of the recursive function will be
241/// at most 90.
242pub const MAX_SPARSE_DEPTH: u32 = 100;
243
244#[cfg(test)]
245pub(crate) mod tests;
246
247pub use crate::sparse_errors::SparseError;
248pub use crate::sparse_state::{SparseFileFormat, SparseState, SparseStateFile};
249use getset::{CopyGetters, Getters, MutGetters};
250use serde::{de::DeserializeOwned, Deserialize, Serialize};
251use serde_json::Value;
252pub use sparsable::Sparsable as SparsableTrait;
253pub use sparse_metadata::SparseMetadata;
254pub use sparse_pointed_value::SparsePointedValue;
255pub use sparse_pointer::{SparsePointer, SparsePointerRaw};
256pub use sparse_ref::SparseRef;
257pub use sparse_ref_raw::SparseRefRaw;
258pub use sparse_ref_raw_inline::SparseRefRawInline;
259pub use sparse_root::SparseRoot;
260pub use sparse_selector::SparseSelector;
261pub use sparse_value::SparseValue;
262pub use sparse_value_mut::SparseValueMut;
263pub use sppparse_derive::Sparsable;
264
265use std::cell::RefCell;
266use std::collections::HashMap;
267use std::convert::From;
268use std::path::PathBuf;
269use std::rc::Rc;