1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// =============================================================================
// Copyright (c) 2025 - 2026 Haixing Hu.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0.
// =============================================================================
//! Defines the coarse top-level JSON kinds used by constrained decode methods.
use std::fmt;
use std::str::FromStr;
use serde_json::Value;
/// Represents the top-level kind of a parsed JSON value.
///
/// The decoder uses this type to report whether the parsed value is an object,
/// an array, or any other scalar-like JSON value.
///
/// # Examples
///
/// ```
/// use qubit_json::decode::JsonRootKind;
///
/// let top_level_kind = JsonRootKind::Other;
/// assert_eq!(top_level_kind.to_string(), "other");
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum JsonRootKind {
/// Indicates that the parsed top-level value is a JSON object.
Object,
/// Indicates that the parsed top-level value is a JSON array.
Array,
/// Indicates that the parsed top-level value is neither an object nor an
/// array.
Other,
}
impl JsonRootKind {
/// Classifies the top-level kind of `value`.
///
/// This helper is used internally by constrained decode methods and may
/// also be useful to callers inspecting decoded [`Value`] instances.
///
/// # Parameters
///
/// * `value` - JSON value to classify.
///
/// # Returns
///
/// [`Self::Object`] for objects, [`Self::Array`] for arrays, and
/// [`Self::Other`] for scalar-like values.
#[must_use]
#[inline]
pub fn of(value: &Value) -> Self {
match value {
Value::Object(_) => Self::Object,
Value::Array(_) => Self::Array,
_ => Self::Other,
}
}
/// Provisionally classifies normalized JSON text by its first JSON token.
///
/// This helper does not validate JSON syntax. The decoder uses the result
/// only as a pre-parse top-level-kind hint.
///
/// # Parameters
///
/// * `value` - Normalized JSON text to inspect.
///
/// # Returns
///
/// [`Self::Object`] when the first token is `{`, [`Self::Array`] when it is
/// `[`, and [`Self::Other`] otherwise.
pub(crate) fn of_normalized_json(value: &str) -> Self {
match value
.bytes()
.find(|byte| !matches!(*byte, b' ' | b'\n' | b'\r' | b'\t'))
{
Some(b'{') => Self::Object,
Some(b'[') => Self::Array,
_ => Self::Other,
}
}
}
impl From<&Value> for JsonRootKind {
/// Classifies a borrowed dynamic JSON value.
///
/// # Parameters
///
/// * `value` - JSON value to classify.
///
/// # Returns
///
/// The value's coarse top-level kind.
#[inline(always)]
fn from(value: &Value) -> Self {
Self::of(value)
}
}
impl fmt::Display for JsonRootKind {
/// Writes the stable lowercase name of this top-level kind.
///
/// # Parameters
///
/// * `f` - Destination formatter.
///
/// # Returns
///
/// `Ok(())` when the kind name is written successfully.
///
/// # Errors
///
/// Returns a formatting error when the destination rejects the write.
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self {
Self::Object => "object",
Self::Array => "array",
Self::Other => "other",
};
f.write_str(name)
}
}
impl FromStr for JsonRootKind {
type Err = &'static str;
/// Parses a top-level kind name without ASCII case sensitivity.
///
/// # Parameters
///
/// * `value` - Kind name to parse.
///
/// # Returns
///
/// The matching top-level kind.
///
/// # Errors
///
/// Returns a static diagnostic when `value` is not a known kind name.
fn from_str(value: &str) -> Result<Self, Self::Err> {
if value.eq_ignore_ascii_case("object") {
Ok(Self::Object)
} else if value.eq_ignore_ascii_case("array") {
Ok(Self::Array)
} else if value.eq_ignore_ascii_case("other") {
Ok(Self::Other)
} else {
Err("unknown JsonRootKind")
}
}
}