1pub mod cmp;
4#[cfg(feature = "conformance")]
5pub mod conformance;
6pub mod numeric;
7#[cfg(feature = "serde_json")]
9pub mod numeric_check;
10pub mod types;
11pub mod unique;
12
13#[cfg(feature = "jsonb")]
14pub mod jsonb;
15#[cfg(feature = "magnus")]
16mod magnus;
17#[cfg(feature = "pyo3")]
18mod pyo3;
19#[cfg(feature = "serde_json")]
20mod serde_json;
21mod serde_number;
22
23#[cfg(feature = "jsonb")]
24pub use jsonb::{Jsonb, JsonbNode};
25#[cfg(feature = "magnus")]
26pub use magnus::{
27 child as magnus_child, invalidate_members_cache as magnus_invalidate_members_cache,
28 is_object as magnus_is_object, object_values as magnus_object_values,
29 probe_root as magnus_probe_root, string_node as magnus_string_node,
30 take_pending_error as magnus_take_pending_error, Magnus, PendingError,
31 PendingErrorScope as MagnusPendingErrorScope, RbNode,
32};
33#[cfg(feature = "pyo3")]
34pub use pyo3::{
35 narrow_array, narrow_object, object_values, probe_root, take_pending_error, PendingErrorScope,
36 Pyo3,
37};
38#[cfg(feature = "serde_json")]
39pub use serde_json::SerdeJson;
40
41use std::{borrow::Cow, fmt, sync::OnceLock};
42
43use ::serde_json::Value;
44
45use crate::types::JsonType;
46
47pub enum LazyInstance<'a> {
49 Ready(Cow<'a, Value>),
50 Deferred {
53 bytes: &'a [u8],
54 tag: u32,
55 make: fn(&[u8], u32) -> Value,
58 cell: OnceLock<Cow<'static, Value>>,
61 },
62}
63
64impl<'a> From<&'a Value> for LazyInstance<'a> {
65 fn from(value: &'a Value) -> Self {
66 LazyInstance::Ready(Cow::Borrowed(value))
67 }
68}
69
70impl<'a> LazyInstance<'a> {
71 pub fn get(&self) -> &Cow<'a, Value> {
73 match self {
74 LazyInstance::Ready(value) => value,
75 LazyInstance::Deferred {
76 bytes,
77 tag,
78 make,
79 cell,
80 } => cell.get_or_init(|| Cow::Owned(make(bytes, *tag))),
81 }
82 }
83
84 #[must_use]
86 pub fn into_cow(self) -> Cow<'a, Value> {
87 match self {
88 LazyInstance::Ready(value) => value,
89 LazyInstance::Deferred {
90 bytes,
91 tag,
92 make,
93 cell,
94 } => cell
95 .into_inner()
96 .unwrap_or_else(|| Cow::Owned(make(bytes, tag))),
97 }
98 }
99}
100
101impl fmt::Debug for LazyInstance<'_> {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 fmt::Debug::fmt(self.get(), f)
104 }
105}
106
107pub trait Json: Sized + Send + Sync + 'static {
109 type Node<'a>: Node<'a, Self>;
110
111 type PreparedKey: Send + Sync;
113
114 const KEYS_PER_LOOKUP: usize = 0;
118
119 type StringBuffer: Default;
121
122 fn prepare_key(key: &str) -> Self::PreparedKey;
123
124 fn with_string_node<T>(
132 buffer: &mut Self::StringBuffer,
133 string: &str,
134 f: impl FnOnce(Self::Node<'_>) -> T,
135 ) -> T;
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
140pub struct NodeIdentity {
141 address: usize,
142 tag: u32,
143}
144
145impl NodeIdentity {
146 #[must_use]
148 pub fn new(address: usize) -> Self {
149 Self { address, tag: 0 }
150 }
151
152 #[must_use]
154 pub fn tagged(address: usize, tag: u32) -> Self {
155 Self { address, tag }
156 }
157}
158
159pub trait JsonNumber {
161 fn as_u64(&self) -> Option<u64>;
162 fn as_i64(&self) -> Option<i64>;
163 fn as_f64(&self) -> Option<f64>;
164
165 fn as_str(&self) -> Cow<'_, str>;
167
168 fn to_number(&self) -> Cow<'_, ::serde_json::Number>;
170
171 fn is_integer(&self) -> bool {
174 crate::types::number_is_integer(&self.to_number())
175 }
176
177 fn is_written_as_integer(&self) -> bool {
183 self.as_u64().is_some()
184 || self.as_i64().is_some()
185 || !self.as_str().contains(['.', 'e', 'E'])
186 }
187}
188
189pub trait Node<'a, F: Json>: Clone {
191 type Object: Object<'a, F, Node = Self>;
192 type Array: Array<'a, F, Node = Self>;
193 type Number: JsonNumber;
194
195 fn as_object(&self) -> Option<Self::Object>;
196 fn as_array(&self) -> Option<Self::Array>;
197 fn as_string(&self) -> Option<Cow<'a, str>>;
198
199 fn as_number(&self) -> Option<Self::Number>;
200 fn as_boolean(&self) -> Option<bool>;
201 fn is_null(&self) -> bool;
202
203 fn is_number(&self) -> bool {
205 self.as_number().is_some()
206 }
207
208 fn is_string(&self) -> bool {
209 self.json_type() == JsonType::String
210 }
211
212 fn json_type(&self) -> JsonType;
214
215 fn string_length(&self) -> Option<u64> {
217 self.as_string().map(|string| string.chars().count() as u64)
218 }
219
220 fn equals_value(&self, expected: &Value) -> bool {
222 crate::cmp::equal(&self.to_value(), expected)
223 }
224
225 fn to_value(&self) -> Cow<'a, Value>;
228
229 fn lazy_value(&self) -> LazyInstance<'a> {
232 LazyInstance::Ready(self.to_value())
233 }
234
235 fn identity(&self) -> Option<NodeIdentity>;
242
243 fn container_identity(&self) -> Option<NodeIdentity> {
244 if matches!(self.json_type(), JsonType::Object | JsonType::Array) {
245 self.identity()
246 } else {
247 None
248 }
249 }
250}
251
252pub trait Object<'a, F: Json> {
253 type Node: Node<'a, F>;
254 type MemberName: AsRef<str> + Into<Cow<'a, str>>;
255 type MembersIter: Iterator<Item = (Self::MemberName, Self::Node)>;
256
257 fn len(&self) -> usize;
258 fn is_empty(&self) -> bool {
259 self.len() == 0
260 }
261 fn get(&self, key: &F::PreparedKey) -> Option<Self::Node>;
262 fn members(&self) -> Self::MembersIter;
263}
264
265#[allow(clippy::len_without_is_empty)]
267pub trait Array<'a, F: Json> {
268 type Node: Node<'a, F>;
269 type ElementsIter: Iterator<Item = Self::Node>;
270
271 fn len(&self) -> usize;
272 fn elements(&self) -> Self::ElementsIter;
273
274 fn is_unique(&self) -> bool {
276 let values: Vec<Cow<'a, Value>> =
277 self.elements().map(|element| element.to_value()).collect();
278 crate::unique::is_unique(&values)
279 }
280}