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;
19
20#[cfg(feature = "magnus")]
21pub use magnus::{
22 child as magnus_child, invalidate_members_cache as magnus_invalidate_members_cache,
23 is_object as magnus_is_object, probe_root as magnus_probe_root,
24 take_pending_error as magnus_take_pending_error, Magnus, PendingError,
25 PendingErrorScope as MagnusPendingErrorScope, RbNode,
26};
27#[cfg(feature = "pyo3")]
28pub use pyo3::{probe_root, take_pending_error, PendingErrorScope, Pyo3};
29#[cfg(feature = "serde_json")]
30pub use serde_json::SerdeJson;
31
32use std::{borrow::Cow, fmt, sync::OnceLock};
33
34use ::serde_json::Value;
35
36use crate::types::JsonType;
37
38pub enum LazyInstance<'a> {
40 Ready(Cow<'a, Value>),
41 Deferred {
44 bytes: &'a [u8],
45 tag: u32,
46 make: fn(&[u8], u32) -> Value,
49 cell: OnceLock<Cow<'static, Value>>,
52 },
53}
54
55impl<'a> LazyInstance<'a> {
56 pub fn get(&self) -> &Cow<'a, Value> {
58 match self {
59 LazyInstance::Ready(value) => value,
60 LazyInstance::Deferred {
61 bytes,
62 tag,
63 make,
64 cell,
65 } => cell.get_or_init(|| Cow::Owned(make(bytes, *tag))),
66 }
67 }
68
69 #[must_use]
71 pub fn into_cow(self) -> Cow<'a, Value> {
72 match self {
73 LazyInstance::Ready(value) => value,
74 LazyInstance::Deferred {
75 bytes,
76 tag,
77 make,
78 cell,
79 } => cell
80 .into_inner()
81 .unwrap_or_else(|| Cow::Owned(make(bytes, tag))),
82 }
83 }
84}
85
86impl fmt::Debug for LazyInstance<'_> {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 fmt::Debug::fmt(self.get(), f)
89 }
90}
91
92pub trait Json: Sized + Send + Sync + 'static {
94 type Node<'a>: Node<'a, Self>;
95
96 type PreparedKey: Send + Sync;
98
99 type StringBuffer: Default;
101
102 fn prepare_key(key: &str) -> Self::PreparedKey;
103
104 fn with_string_node<T>(
112 buffer: &mut Self::StringBuffer,
113 string: &str,
114 f: impl FnOnce(Self::Node<'_>) -> T,
115 ) -> T;
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
120pub struct NodeIdentity {
121 address: usize,
122 tag: u32,
123}
124
125impl NodeIdentity {
126 #[must_use]
128 pub fn new(address: usize) -> Self {
129 Self { address, tag: 0 }
130 }
131
132 #[must_use]
134 pub fn tagged(address: usize, tag: u32) -> Self {
135 Self { address, tag }
136 }
137}
138
139pub trait JsonNumber {
141 fn as_u64(&self) -> Option<u64>;
142 fn as_i64(&self) -> Option<i64>;
143 fn as_f64(&self) -> Option<f64>;
144
145 fn as_str(&self) -> Cow<'_, str>;
147
148 fn to_number(&self) -> Cow<'_, ::serde_json::Number>;
150
151 fn is_integer(&self) -> bool {
154 crate::types::number_is_integer(&self.to_number())
155 }
156}
157
158pub trait Node<'a, F: Json>: Clone {
160 type Object: Object<'a, F, Node = Self>;
161 type Array: Array<'a, F, Node = Self>;
162 type Number: JsonNumber;
163
164 fn as_object(&self) -> Option<Self::Object>;
165 fn as_array(&self) -> Option<Self::Array>;
166 fn as_string(&self) -> Option<Cow<'a, str>>;
167
168 fn as_number(&self) -> Option<Self::Number>;
169 fn as_boolean(&self) -> Option<bool>;
170 fn is_null(&self) -> bool;
171
172 fn is_number(&self) -> bool {
174 self.as_number().is_some()
175 }
176
177 fn is_string(&self) -> bool {
178 self.json_type() == JsonType::String
179 }
180
181 fn json_type(&self) -> JsonType;
183
184 fn string_length(&self) -> Option<u64> {
186 self.as_string().map(|string| string.chars().count() as u64)
187 }
188
189 fn equals_value(&self, expected: &Value) -> bool {
191 crate::cmp::equal(&self.to_value(), expected)
192 }
193
194 fn to_value(&self) -> Cow<'a, Value>;
197
198 fn lazy_value(&self) -> LazyInstance<'a> {
201 LazyInstance::Ready(self.to_value())
202 }
203
204 fn identity(&self) -> Option<NodeIdentity>;
211
212 fn container_identity(&self) -> Option<NodeIdentity> {
213 if matches!(self.json_type(), JsonType::Object | JsonType::Array) {
214 self.identity()
215 } else {
216 None
217 }
218 }
219}
220
221pub trait Object<'a, F: Json> {
222 type Node: Node<'a, F>;
223 type MemberName: AsRef<str> + Into<Cow<'a, str>>;
224 type MembersIter: Iterator<Item = (Self::MemberName, Self::Node)>;
225
226 fn len(&self) -> usize;
227 fn is_empty(&self) -> bool {
228 self.len() == 0
229 }
230 fn get(&self, key: &F::PreparedKey) -> Option<Self::Node>;
231 fn members(&self) -> Self::MembersIter;
232}
233
234#[allow(clippy::len_without_is_empty)]
236pub trait Array<'a, F: Json> {
237 type Node: Node<'a, F>;
238 type ElementsIter: Iterator<Item = Self::Node>;
239
240 fn len(&self) -> usize;
241 fn elements(&self) -> Self::ElementsIter;
242
243 fn is_unique(&self) -> bool {
245 let values: Vec<Cow<'a, Value>> =
246 self.elements().map(|element| element.to_value()).collect();
247 crate::unique::is_unique(&values)
248 }
249}