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::{inspect, narrow_array, narrow_object, object_values, stock_enum_value, Pyo3};
35#[cfg(feature = "serde_json")]
36pub use serde_json::SerdeJson;
37
38use std::{borrow::Cow, fmt, sync::OnceLock};
39
40use ::serde_json::Value;
41
42use crate::types::JsonType;
43
44pub enum LazyInstance<'a> {
46 Ready(Cow<'a, Value>),
47 Deferred {
50 bytes: &'a [u8],
51 tag: u32,
52 make: fn(&[u8], u32) -> Value,
55 cell: OnceLock<Cow<'static, Value>>,
58 },
59}
60
61impl<'a> From<&'a Value> for LazyInstance<'a> {
62 fn from(value: &'a Value) -> Self {
63 LazyInstance::Ready(Cow::Borrowed(value))
64 }
65}
66
67impl<'a> LazyInstance<'a> {
68 pub fn get(&self) -> &Cow<'a, Value> {
70 match self {
71 LazyInstance::Ready(value) => value,
72 LazyInstance::Deferred {
73 bytes,
74 tag,
75 make,
76 cell,
77 } => cell.get_or_init(|| Cow::Owned(make(bytes, *tag))),
78 }
79 }
80
81 #[must_use]
83 pub fn into_cow(self) -> Cow<'a, Value> {
84 match self {
85 LazyInstance::Ready(value) => value,
86 LazyInstance::Deferred {
87 bytes,
88 tag,
89 make,
90 cell,
91 } => cell
92 .into_inner()
93 .unwrap_or_else(|| Cow::Owned(make(bytes, tag))),
94 }
95 }
96}
97
98impl fmt::Debug for LazyInstance<'_> {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 fmt::Debug::fmt(self.get(), f)
101 }
102}
103
104pub trait Json: Sized + Send + Sync + 'static {
106 type Node<'a>: Node<'a, Self>;
107
108 type PreparedKey: Send + Sync;
110
111 const KEYS_PER_LOOKUP: usize = 0;
115
116 type StringBuffer: Default;
118
119 fn prepare_key(key: &str) -> Self::PreparedKey;
120
121 fn with_string_node<T>(
129 buffer: &mut Self::StringBuffer,
130 string: &str,
131 f: impl FnOnce(Self::Node<'_>) -> T,
132 ) -> T;
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
137pub struct NodeIdentity {
138 address: usize,
139 tag: u32,
140}
141
142impl NodeIdentity {
143 #[must_use]
145 pub fn new(address: usize) -> Self {
146 Self { address, tag: 0 }
147 }
148
149 #[must_use]
151 pub fn tagged(address: usize, tag: u32) -> Self {
152 Self { address, tag }
153 }
154}
155
156pub trait JsonNumber {
158 fn as_u64(&self) -> Option<u64>;
159 fn as_i64(&self) -> Option<i64>;
160 fn as_f64(&self) -> Option<f64>;
161
162 fn as_str(&self) -> Cow<'_, str>;
164
165 fn to_number(&self) -> Cow<'_, ::serde_json::Number>;
167
168 fn is_integer(&self) -> bool {
171 crate::types::number_is_integer(&self.to_number())
172 }
173
174 fn is_written_as_integer(&self) -> bool {
180 self.as_u64().is_some()
181 || self.as_i64().is_some()
182 || !self.as_str().contains(['.', 'e', 'E'])
183 }
184}
185
186pub trait Node<'a, F: Json>: Clone {
188 type Object: Object<'a, F, Node = Self>;
189 type Array: Array<'a, F, Node = Self>;
190 type Number: JsonNumber;
191
192 fn as_object(&self) -> Option<Self::Object>;
193 fn as_array(&self) -> Option<Self::Array>;
194 fn as_string(&self) -> Option<Cow<'a, str>>;
195
196 fn as_number(&self) -> Option<Self::Number>;
197 fn as_boolean(&self) -> Option<bool>;
198 fn is_null(&self) -> bool;
199
200 fn is_number(&self) -> bool {
202 self.as_number().is_some()
203 }
204
205 fn is_string(&self) -> bool {
206 self.json_type() == JsonType::String
207 }
208
209 fn json_type(&self) -> JsonType;
211
212 fn string_length(&self) -> Option<u64> {
214 self.as_string().map(|string| string.chars().count() as u64)
215 }
216
217 fn equals_value(&self, expected: &Value) -> bool {
219 crate::cmp::equal(&self.to_value(), expected)
220 }
221
222 fn to_value(&self) -> Cow<'a, Value>;
225
226 fn lazy_value(&self) -> LazyInstance<'a> {
229 LazyInstance::Ready(self.to_value())
230 }
231
232 fn identity(&self) -> Option<NodeIdentity>;
239
240 fn container_identity(&self) -> Option<NodeIdentity> {
241 if matches!(self.json_type(), JsonType::Object | JsonType::Array) {
242 self.identity()
243 } else {
244 None
245 }
246 }
247}
248
249pub trait Object<'a, F: Json> {
250 type Node: Node<'a, F>;
251 type MemberName: AsRef<str> + Into<Cow<'a, str>>;
252 type MembersIter: Iterator<Item = (Self::MemberName, Self::Node)>;
253
254 fn len(&self) -> usize;
255 fn is_empty(&self) -> bool {
256 self.len() == 0
257 }
258 fn get(&self, key: &F::PreparedKey) -> Option<Self::Node>;
259 fn members(&self) -> Self::MembersIter;
260}
261
262#[allow(clippy::len_without_is_empty)]
264pub trait Array<'a, F: Json> {
265 type Node: Node<'a, F>;
266 type ElementsIter: Iterator<Item = Self::Node>;
267
268 fn len(&self) -> usize;
269 fn elements(&self) -> Self::ElementsIter;
270
271 fn is_unique(&self) -> bool {
273 let values: Vec<Cow<'a, Value>> =
274 self.elements().map(|element| element.to_value()).collect();
275 crate::unique::is_unique(&values)
276 }
277}