1use std::{
2 borrow::Cow,
3 fmt::{self, Debug, Display},
4 hash::Hash,
5 str::from_utf8_unchecked,
6 sync::{
7 atomic::{AtomicPtr, Ordering},
8 Arc,
9 },
10};
11
12use faststr::FastStr;
13
14use crate::{
15 from_str, get_unchecked,
16 index::Index,
17 input::JsonSlice,
18 lazyvalue::iterator::{ArrayJsonIter, ObjectJsonIter},
19 serde::Number,
20 JsonType, JsonValueTrait, RawNumber,
21};
22
23#[derive(Clone)]
121pub struct LazyValue<'a> {
122 pub(crate) raw: JsonSlice<'a>,
124 pub(crate) inner: Inner,
125}
126
127pub(crate) struct Inner {
128 pub(crate) status: HasEsc,
129 pub(crate) unescaped: AtomicPtr<()>,
130}
131
132impl Inner {
133 pub(crate) fn no_escaped(&self) -> bool {
134 self.status == HasEsc::None
135 }
136
137 pub(crate) fn parse_from(&self, raw: &[u8]) -> Option<&str> {
138 let ptr = self.unescaped.load(Ordering::Acquire);
139 if !ptr.is_null() {
140 return Some(unsafe { &*(ptr as *const String) });
141 }
142
143 unsafe {
144 let parsed: String = crate::from_slice_unchecked(raw).ok()?;
145 let parsed = Arc::into_raw(Arc::new(parsed)) as *mut ();
146 match self.unescaped.compare_exchange_weak(
147 ptr,
148 parsed,
149 Ordering::AcqRel,
150 Ordering::Acquire,
151 ) {
152 Ok(_) => Some(&*(parsed as *const String)),
153 Err(e) => {
154 Arc::decrement_strong_count(parsed);
155 Some(&*(e as *const String))
156 }
157 }
158 }
159 }
160}
161impl Default for Inner {
162 fn default() -> Self {
163 Self {
164 status: HasEsc::None,
165 unescaped: AtomicPtr::new(std::ptr::null_mut()),
166 }
167 }
168}
169
170impl Clone for Inner {
171 fn clone(&self) -> Self {
172 let ptr = if !self.no_escaped() {
173 let ptr = self.unescaped.load(Ordering::Acquire);
175 if !ptr.is_null() {
176 unsafe { Arc::increment_strong_count(ptr as *const String) };
177 }
178 ptr
179 } else {
180 std::ptr::null_mut()
181 };
182 Self {
183 status: self.status,
184 unescaped: AtomicPtr::new(ptr),
185 }
186 }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq)]
190pub(crate) enum HasEsc {
191 None,
192 Yes,
193 Possible,
194}
195
196impl Default for LazyValue<'_> {
197 fn default() -> Self {
198 Self {
199 raw: JsonSlice::Raw(&b"null"[..]),
200 inner: Inner::default(),
201 }
202 }
203}
204
205impl Drop for Inner {
206 fn drop(&mut self) {
207 if self.no_escaped() {
208 return;
209 }
210
211 let ptr = self.unescaped.load(Ordering::Acquire);
212 if !ptr.is_null() {
213 unsafe { Arc::decrement_strong_count(ptr as *const String) };
214 }
215 }
216}
217
218impl<'a> Debug for LazyValue<'a> {
219 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
220 formatter
221 .debug_struct("LazyValue")
222 .field("raw json", &format_args!("{}", &self.as_raw_str()))
223 .field("has_escaped", &self.inner.status)
224 .finish()
225 }
226}
227
228impl<'a> Display for LazyValue<'a> {
229 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230 f.write_str(self.as_raw_str())
231 }
232}
233
234impl PartialEq for LazyValue<'_> {
235 fn eq(&self, other: &Self) -> bool {
236 self.raw.as_ref() == other.raw.as_ref()
237 }
238}
239
240impl PartialOrd for LazyValue<'_> {
241 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
242 Some(self.cmp(other))
243 }
244}
245
246impl<'a> Ord for LazyValue<'a> {
247 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
248 self.raw.as_ref().cmp(other.raw.as_ref())
249 }
250}
251
252impl<'a> Eq for LazyValue<'a> {}
253
254impl<'a> Hash for LazyValue<'a> {
255 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
256 self.raw.as_ref().hash(state)
257 }
258}
259
260impl<'a> JsonValueTrait for LazyValue<'a> {
261 type ValueType<'v>
262 = LazyValue<'v>
263 where
264 Self: 'v;
265
266 fn as_bool(&self) -> Option<bool> {
267 match self.raw.as_ref() {
268 b"true" => Some(true),
269 b"false" => Some(false),
270 _ => None,
271 }
272 }
273
274 fn as_number(&self) -> Option<Number> {
275 from_str(self.as_raw_str()).ok()
276 }
277
278 fn as_raw_number(&self) -> Option<RawNumber> {
279 from_str(self.as_raw_str()).ok()
280 }
281
282 fn as_str(&self) -> Option<&str> {
283 if !self.is_str() {
284 return None;
285 }
286
287 if self.inner.no_escaped() {
288 let origin = {
290 let raw = self.as_raw_str().as_bytes();
291 &raw[1..raw.len() - 1]
292 };
293 Some(unsafe { from_utf8_unchecked(origin) })
294 } else {
295 self.inner.parse_from(self.raw.as_ref())
296 }
297 }
298
299 fn get_type(&self) -> crate::JsonType {
300 match self.raw.as_ref()[0] {
301 b'-' | b'0'..=b'9' => JsonType::Number,
302 b'"' => JsonType::String,
303 b'{' => JsonType::Object,
304 b'[' => JsonType::Array,
305 b't' | b'f' => JsonType::Boolean,
306 b'n' => JsonType::Null,
307 _ => unreachable!(),
308 }
309 }
310
311 fn get<I: Index>(&self, index: I) -> Option<LazyValue<'_>> {
312 if let Some(key) = index.as_key() {
313 self.get_key(key)
314 } else if let Some(index) = index.as_index() {
315 self.get_index(index)
316 } else {
317 unreachable!("index must be key or index")
318 }
319 }
320
321 fn pointer<P: IntoIterator>(&self, path: P) -> Option<LazyValue<'_>>
322 where
323 P::Item: Index,
324 {
325 let path = path.into_iter();
326 match &self.raw {
327 JsonSlice::Raw(r) => unsafe { get_unchecked(*r, path).ok() },
330 JsonSlice::FastStr(f) => unsafe { get_unchecked(f, path).ok() },
331 }
332 }
333}
334
335impl<'a> LazyValue<'a> {
336 pub fn as_raw_str(&self) -> &str {
347 unsafe { from_utf8_unchecked(self.raw.as_ref()) }
351 }
352
353 pub fn as_raw_cow(&self) -> Cow<'a, str> {
364 match &self.raw {
365 JsonSlice::Raw(r) => Cow::Borrowed(unsafe { from_utf8_unchecked(r) }),
366 JsonSlice::FastStr(f) => Cow::Owned(f.to_string()),
367 }
368 }
369
370 pub fn as_raw_faststr(&self) -> FastStr {
390 match &self.raw {
391 JsonSlice::Raw(r) => unsafe { FastStr::new_u8_slice_unchecked(r) },
392 JsonSlice::FastStr(f) => f.clone(),
393 }
394 }
395
396 pub fn into_object_iter(mut self) -> Option<ObjectJsonIter<'a>> {
397 if self.is_object() {
398 Some(ObjectJsonIter::new_inner(std::mem::take(&mut self.raw)))
399 } else {
400 None
401 }
402 }
403
404 pub fn into_array_iter(mut self) -> Option<ArrayJsonIter<'a>> {
405 if self.is_array() {
406 Some(ArrayJsonIter::new_inner(std::mem::take(&mut self.raw)))
407 } else {
408 None
409 }
410 }
411
412 pub(crate) fn get_index(&'a self, index: usize) -> Option<Self> {
414 let path = [index];
415 match &self.raw {
416 JsonSlice::Raw(r) => unsafe { get_unchecked(*r, path.iter()).ok() },
419 JsonSlice::FastStr(f) => unsafe { get_unchecked(f, path.iter()).ok() },
420 }
421 }
422
423 pub(crate) fn get_key(&'a self, key: &str) -> Option<Self> {
425 let path = [key];
426 match &self.raw {
427 JsonSlice::Raw(r) => unsafe { get_unchecked(*r, path.iter()).ok() },
430 JsonSlice::FastStr(f) => unsafe { get_unchecked(f, path.iter()).ok() },
431 }
432 }
433
434 pub(crate) fn new(raw: JsonSlice<'a>, status: HasEsc) -> Self {
435 Self {
436 raw,
437 inner: Inner {
438 status,
439 unescaped: AtomicPtr::new(std::ptr::null_mut()),
440 },
441 }
442 }
443}
444
445#[cfg(test)]
446mod test {
447 use super::*;
448 use crate::{pointer, to_array_iter};
449
450 const TEST_JSON: &str = r#"{
451 "bool": true,
452 "int": -1,
453 "uint": 0,
454 "float": 1.1,
455 "string": "hello",
456 "string_escape": "\"hello\"",
457 "array": [1,2,3],
458 "object": {"a":"aaa"},
459 "strempty": "",
460 "objempty": {},
461 "arrempty": [],
462 "arrempty": []
463 }"#;
464
465 #[test]
466 fn test_lazyvalue_export() {
467 let f = FastStr::new(TEST_JSON);
468 let value = unsafe { get_unchecked(&f, pointer![].iter()).unwrap() };
469 assert_eq!(value.get("int").unwrap().as_raw_str(), "-1");
470 assert_eq!(
471 value.get("array").unwrap().as_raw_faststr().as_str(),
472 "[1,2,3]"
473 );
474 assert_eq!(
475 value
476 .pointer(pointer!["object", "a"])
477 .unwrap()
478 .as_raw_str()
479 .as_bytes(),
480 b"\"aaa\""
481 );
482 assert!(value.pointer(pointer!["objempty", "a"]).is_none());
483 }
484
485 #[test]
486 fn test_lazyvalue_is() {
487 let value = unsafe { get_unchecked(TEST_JSON, pointer![].iter()).unwrap() };
488 assert!(value.get("bool").is_boolean());
489 assert!(value.get("bool").is_true());
490 assert!(value.get("uint").is_u64());
491 assert!(value.get("uint").is_number());
492 assert!(value.get("int").is_i64());
493 assert!(value.get("float").is_f64());
494 assert!(value.get("string").is_str());
495 assert!(value.get("array").is_array());
496 assert!(value.get("object").is_object());
497 assert!(value.get("strempty").is_str());
498 assert!(value.get("objempty").is_object());
499 assert!(value.get("arrempty").is_array());
500 }
501
502 #[test]
503 fn test_lazyvalue_get() {
504 let value = unsafe { get_unchecked(TEST_JSON, pointer![].iter()).unwrap() };
505 assert_eq!(value.get("int").as_i64().unwrap(), -1);
506 assert_eq!(value.pointer(pointer!["array", 2]).as_u64().unwrap(), 3);
507 assert_eq!(
508 value.pointer(pointer!["object", "a"]).as_str().unwrap(),
509 "aaa"
510 );
511 assert!(value.pointer(pointer!["object", "b"]).is_none());
512 assert!(value.pointer(pointer!["object", "strempty"]).is_none());
513 assert_eq!(value.pointer(pointer!["objempty", "a"]).as_str(), None);
514 assert!(value.pointer(pointer!["arrempty", 1]).is_none());
515 assert!(value.pointer(pointer!["array", 3]).is_none());
516 assert!(value.pointer(pointer!["array", 4]).is_none());
517 assert_eq!(value.pointer(pointer!["arrempty", 1]).as_str(), None);
518 assert_eq!(value.get("string").as_str().unwrap(), "hello");
519
520 let value = unsafe { get_unchecked(TEST_JSON, pointer![].iter()).unwrap() };
521 assert_eq!(value.get("string_escape").as_str().unwrap(), "\"hello\"");
522
523 let value = unsafe { get_unchecked(TEST_JSON, pointer![].iter()).unwrap() };
524 assert!(value.get("int").as_str().is_none());
525 assert_eq!(value.get("int").as_i64(), Some(-1));
526 assert_eq!(value.get("uint").as_i64(), Some(0));
527 assert_eq!(value.get("float").as_f64(), Some(1.1));
528 }
529
530 #[test]
531 fn test_lazyvalue_cow() {
532 fn get_cow(json: &str) -> Option<Cow<'_, str>> {
533 to_array_iter(json)
534 .next()
535 .map(|val| val.unwrap().as_raw_cow())
536 }
537
538 assert_eq!(get_cow("[true]").unwrap(), "true");
539 }
540}