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 = "magnus")]
14mod magnus;
15#[cfg(feature = "pyo3")]
16mod pyo3;
17#[cfg(feature = "serde_json")]
18mod serde_json;
19mod serde_number;
20
21#[cfg(feature = "magnus")]
22pub use magnus::{
23 child as magnus_child, invalidate_members_cache as magnus_invalidate_members_cache,
24 is_object as magnus_is_object, probe_root as magnus_probe_root,
25 take_pending_error as magnus_take_pending_error, Magnus, PendingError,
26 PendingErrorScope as MagnusPendingErrorScope, RbNode,
27};
28#[cfg(feature = "pyo3")]
29pub use pyo3::{probe_root, take_pending_error, PendingErrorScope, Pyo3};
30#[cfg(feature = "serde_json")]
31pub use serde_json::SerdeJson;
32
33use std::{borrow::Cow, fmt, sync::OnceLock};
34
35use ::serde_json::Value;
36
37use crate::types::JsonType;
38
39pub enum LazyInstance<'a> {
41 Ready(Cow<'a, Value>),
42 Deferred {
45 bytes: &'a [u8],
46 tag: u32,
47 make: fn(&[u8], u32) -> Value,
50 cell: OnceLock<Cow<'static, Value>>,
53 },
54}
55
56impl<'a> From<&'a Value> for LazyInstance<'a> {
57 fn from(value: &'a Value) -> Self {
58 LazyInstance::Ready(Cow::Borrowed(value))
59 }
60}
61
62impl<'a> LazyInstance<'a> {
63 pub fn get(&self) -> &Cow<'a, Value> {
65 match self {
66 LazyInstance::Ready(value) => value,
67 LazyInstance::Deferred {
68 bytes,
69 tag,
70 make,
71 cell,
72 } => cell.get_or_init(|| Cow::Owned(make(bytes, *tag))),
73 }
74 }
75
76 #[must_use]
78 pub fn into_cow(self) -> Cow<'a, Value> {
79 match self {
80 LazyInstance::Ready(value) => value,
81 LazyInstance::Deferred {
82 bytes,
83 tag,
84 make,
85 cell,
86 } => cell
87 .into_inner()
88 .unwrap_or_else(|| Cow::Owned(make(bytes, tag))),
89 }
90 }
91}
92
93impl fmt::Debug for LazyInstance<'_> {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 fmt::Debug::fmt(self.get(), f)
96 }
97}
98
99pub trait Json: Sized + Send + Sync + 'static {
101 type Node<'a>: Node<'a, Self>;
102
103 type PreparedKey: Send + Sync;
105
106 const KEYS_PER_LOOKUP: usize = 0;
110
111 type StringBuffer: Default;
113
114 fn prepare_key(key: &str) -> Self::PreparedKey;
115
116 fn with_string_node<T>(
124 buffer: &mut Self::StringBuffer,
125 string: &str,
126 f: impl FnOnce(Self::Node<'_>) -> T,
127 ) -> T;
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
132pub struct NodeIdentity {
133 address: usize,
134 tag: u32,
135}
136
137impl NodeIdentity {
138 #[must_use]
140 pub fn new(address: usize) -> Self {
141 Self { address, tag: 0 }
142 }
143
144 #[must_use]
146 pub fn tagged(address: usize, tag: u32) -> Self {
147 Self { address, tag }
148 }
149}
150
151pub trait JsonNumber {
153 fn as_u64(&self) -> Option<u64>;
154 fn as_i64(&self) -> Option<i64>;
155 fn as_f64(&self) -> Option<f64>;
156
157 fn as_str(&self) -> Cow<'_, str>;
159
160 fn to_number(&self) -> Cow<'_, ::serde_json::Number>;
162
163 fn is_integer(&self) -> bool {
166 crate::types::number_is_integer(&self.to_number())
167 }
168
169 fn is_written_as_integer(&self) -> bool {
175 self.as_u64().is_some()
176 || self.as_i64().is_some()
177 || !self.as_str().contains(['.', 'e', 'E'])
178 }
179}
180
181pub trait Node<'a, F: Json>: Clone {
183 type Object: Object<'a, F, Node = Self>;
184 type Array: Array<'a, F, Node = Self>;
185 type Number: JsonNumber;
186
187 fn as_object(&self) -> Option<Self::Object>;
188 fn as_array(&self) -> Option<Self::Array>;
189 fn as_string(&self) -> Option<Cow<'a, str>>;
190
191 fn as_number(&self) -> Option<Self::Number>;
192 fn as_boolean(&self) -> Option<bool>;
193 fn is_null(&self) -> bool;
194
195 fn is_number(&self) -> bool {
197 self.as_number().is_some()
198 }
199
200 fn is_string(&self) -> bool {
201 self.json_type() == JsonType::String
202 }
203
204 fn json_type(&self) -> JsonType;
206
207 fn string_length(&self) -> Option<u64> {
209 self.as_string().map(|string| string.chars().count() as u64)
210 }
211
212 fn equals_value(&self, expected: &Value) -> bool {
214 crate::cmp::equal(&self.to_value(), expected)
215 }
216
217 fn to_value(&self) -> Cow<'a, Value>;
220
221 fn lazy_value(&self) -> LazyInstance<'a> {
224 LazyInstance::Ready(self.to_value())
225 }
226
227 fn identity(&self) -> Option<NodeIdentity>;
234
235 fn container_identity(&self) -> Option<NodeIdentity> {
236 if matches!(self.json_type(), JsonType::Object | JsonType::Array) {
237 self.identity()
238 } else {
239 None
240 }
241 }
242}
243
244pub trait Object<'a, F: Json> {
245 type Node: Node<'a, F>;
246 type MemberName: AsRef<str> + Into<Cow<'a, str>>;
247 type MembersIter: Iterator<Item = (Self::MemberName, Self::Node)>;
248
249 fn len(&self) -> usize;
250 fn is_empty(&self) -> bool {
251 self.len() == 0
252 }
253 fn get(&self, key: &F::PreparedKey) -> Option<Self::Node>;
254 fn members(&self) -> Self::MembersIter;
255}
256
257#[allow(clippy::len_without_is_empty)]
259pub trait Array<'a, F: Json> {
260 type Node: Node<'a, F>;
261 type ElementsIter: Iterator<Item = Self::Node>;
262
263 fn len(&self) -> usize;
264 fn elements(&self) -> Self::ElementsIter;
265
266 fn is_unique(&self) -> bool {
268 let values: Vec<Cow<'a, Value>> =
269 self.elements().map(|element| element.to_value()).collect();
270 crate::unique::is_unique(&values)
271 }
272}