use alloc::{
borrow::Cow, borrow::ToOwned, boxed::Box, format, string::String, string::ToString, vec::Vec,
};
use core::{fmt::Display, hash::Hash, ops::Range};
use crate::{
DisplayJson, JsonArrayFormatter, JsonFormatter, JsonObjectFormatter, JsonValueKind,
parse::{JsonParser, Jsonc, Plain},
};
pub use crate::parse_error::JsonParseError;
#[derive(Debug, Clone)]
pub struct RawJsonOwned {
text: String,
values: Vec<JsonValueIndexEntry>,
}
impl RawJsonOwned {
pub fn parse<T>(text: T) -> Result<Self, JsonParseError>
where
T: Into<String>,
{
let text = text.into();
let (values, _) = JsonParser::<Plain>::new(&text).parse()?;
Ok(Self { text, values })
}
pub fn parse_jsonc<T>(text: T) -> Result<(Self, Vec<Range<usize>>), JsonParseError>
where
T: Into<String>,
{
let text = text.into();
let (values, comments) = JsonParser::<Jsonc>::new(&text).parse()?;
Ok((Self { text, values }, comments))
}
pub fn object<F>(fmt: F) -> Self
where
F: Fn(&mut JsonObjectFormatter<'_, '_, '_>) -> core::fmt::Result,
{
Self::parse(crate::object(fmt).to_string())
.expect("bug: object formatter must produce valid JSON")
}
pub fn json<F>(fmt: F) -> Self
where
F: Fn(&mut JsonFormatter<'_, '_>) -> core::fmt::Result,
{
Self::parse(crate::json(fmt).to_string())
.expect("bug: json formatter must produce valid JSON")
}
pub fn array<F>(fmt: F) -> Self
where
F: Fn(&mut JsonArrayFormatter<'_, '_, '_>) -> core::fmt::Result,
{
Self::parse(crate::array(fmt).to_string())
.expect("bug: array formatter must produce valid JSON")
}
pub fn text(&self) -> &str {
&self.text
}
pub fn value(&self) -> RawJsonValue<'_, '_> {
RawJsonValue {
json: self.as_raw_json_ref(),
index: 0,
}
}
pub fn get_value_by_position(&self, position: usize) -> Option<RawJsonValue<'_, '_>> {
self.as_raw_json_ref().get_value_by_position(position)
}
pub fn get_value_by_index(&self, index: usize) -> Option<RawJsonValue<'_, '_>> {
(index < self.values.len()).then(|| RawJsonValue {
json: self.as_raw_json_ref(),
index,
})
}
fn as_raw_json_ref(&self) -> RawJsonRef<'_, '_> {
RawJsonRef {
text: &self.text,
values: &self.values,
}
}
}
impl PartialEq for RawJsonOwned {
fn eq(&self, other: &Self) -> bool {
self.text == other.text
}
}
impl Eq for RawJsonOwned {}
impl PartialOrd for RawJsonOwned {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RawJsonOwned {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.text.cmp(&other.text)
}
}
impl Hash for RawJsonOwned {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.text.hash(state);
}
}
impl Display for RawJsonOwned {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", crate::Json(self))
}
}
impl DisplayJson for RawJsonOwned {
fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> core::fmt::Result {
DisplayJson::fmt(&self.value(), f)
}
}
impl core::str::FromStr for RawJsonOwned {
type Err = JsonParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl<'text, 'raw> TryFrom<RawJsonValue<'text, 'raw>> for RawJsonOwned {
type Error = JsonParseError;
fn try_from(value: RawJsonValue<'text, 'raw>) -> Result<Self, Self::Error> {
Ok(value.extract().into_owned())
}
}
#[derive(Debug, Clone)]
pub struct RawJson<'text> {
text: &'text str,
values: Vec<JsonValueIndexEntry>,
}
impl<'text> RawJson<'text> {
pub fn parse(text: &'text str) -> Result<Self, JsonParseError> {
let (values, _) = JsonParser::<Plain>::new(text).parse()?;
Ok(Self { text, values })
}
pub fn parse_jsonc(text: &'text str) -> Result<(Self, Vec<Range<usize>>), JsonParseError> {
let (values, comments) = JsonParser::<Jsonc>::new(text).parse()?;
Ok((Self { text, values }, comments))
}
pub fn text(&self) -> &'text str {
self.text
}
pub fn value(&self) -> RawJsonValue<'text, '_> {
RawJsonValue {
json: self.as_raw_json_ref(),
index: 0,
}
}
pub fn get_value_by_position(&self, position: usize) -> Option<RawJsonValue<'text, '_>> {
self.as_raw_json_ref().get_value_by_position(position)
}
pub fn get_value_by_index(&self, index: usize) -> Option<RawJsonValue<'text, '_>> {
(index < self.values.len()).then(|| RawJsonValue {
json: self.as_raw_json_ref(),
index,
})
}
pub fn into_owned(self) -> RawJsonOwned {
RawJsonOwned {
text: self.text.to_owned(),
values: self.values,
}
}
fn as_raw_json_ref(&self) -> RawJsonRef<'text, '_> {
RawJsonRef {
text: self.text,
values: &self.values,
}
}
}
impl PartialEq for RawJson<'_> {
fn eq(&self, other: &Self) -> bool {
self.text == other.text
}
}
impl Eq for RawJson<'_> {}
impl PartialOrd for RawJson<'_> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RawJson<'_> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.text.cmp(other.text)
}
}
impl Hash for RawJson<'_> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.text.hash(state);
}
}
impl Display for RawJson<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", crate::Json(self))
}
}
impl DisplayJson for RawJson<'_> {
fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> core::fmt::Result {
DisplayJson::fmt(&self.value(), f)
}
}
impl<'text, 'raw> TryFrom<RawJsonValue<'text, 'raw>> for RawJson<'text> {
type Error = JsonParseError;
fn try_from(value: RawJsonValue<'text, 'raw>) -> Result<Self, Self::Error> {
Ok(value.extract())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct JsonValueIndexEntry {
pub kind: JsonValueKind,
pub escaped: bool,
pub text: Range<usize>,
pub end_index: usize,
}
#[derive(Debug, Clone, Copy)]
struct RawJsonRef<'text, 'raw> {
text: &'text str,
values: &'raw [JsonValueIndexEntry],
}
impl<'text, 'raw> RawJsonRef<'text, 'raw> {
fn get_value_by_position(self, position: usize) -> Option<RawJsonValue<'text, 'raw>> {
let mut value = self.value();
if !value.entry().text.contains(&position) {
return None;
}
while let Some(child) = Children::new(value).find(|c| c.entry().text.contains(&position)) {
value = child;
}
Some(value)
}
fn value(self) -> RawJsonValue<'text, 'raw> {
RawJsonValue {
json: self,
index: 0,
}
}
}
impl PartialEq for RawJsonRef<'_, '_> {
fn eq(&self, other: &Self) -> bool {
self.text == other.text
}
}
impl Eq for RawJsonRef<'_, '_> {}
impl PartialOrd for RawJsonRef<'_, '_> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RawJsonRef<'_, '_> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.text.cmp(other.text)
}
}
impl Hash for RawJsonRef<'_, '_> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.text.hash(state);
}
}
impl Display for RawJsonRef<'_, '_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", crate::Json(self))
}
}
impl DisplayJson for RawJsonRef<'_, '_> {
fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> core::fmt::Result {
DisplayJson::fmt(&self.value(), f)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawJsonValue<'text, 'raw> {
index: usize,
json: RawJsonRef<'text, 'raw>,
}
impl<'text, 'raw> RawJsonValue<'text, 'raw> {
pub fn kind(self) -> JsonValueKind {
self.json.values[self.index].kind
}
pub fn position(self) -> usize {
self.json.values[self.index].text.start
}
pub fn index(self) -> usize {
self.index
}
pub fn parent(self) -> Option<Self> {
if self.index == 0 {
return None;
}
self.json.get_value_by_position(self.position() - 1)
}
pub fn root(self) -> Self {
Self {
json: self.json,
index: 0,
}
}
pub fn as_raw_str(self) -> &'text str {
let text = &self.json.values[self.index].text;
&self.json.text[text.start..text.end]
}
pub fn extract(self) -> RawJson<'text> {
let start_index = self.index;
let end_index = self.entry().end_index;
let start_pos = self.entry().text.start;
let end_pos = self.entry().text.end;
let value_text = &self.json.text[start_pos..end_pos];
let relevant_entries = &self.json.values[start_index..end_index];
let new_values = relevant_entries
.iter()
.map(|entry| JsonValueIndexEntry {
kind: entry.kind,
escaped: entry.escaped,
text: (entry.text.start - start_pos)..(entry.text.end - start_pos),
end_index: entry.end_index - start_index,
})
.collect();
RawJson {
text: value_text,
values: new_values,
}
}
pub fn as_boolean_str(self) -> Result<&'text str, JsonParseError> {
self.expect([JsonValueKind::Boolean])
.map(|v| v.as_raw_str())
}
pub fn as_integer_str(self) -> Result<&'text str, JsonParseError> {
self.expect([JsonValueKind::Integer])
.map(|v| v.as_raw_str())
}
pub fn as_float_str(self) -> Result<&'text str, JsonParseError> {
self.expect([JsonValueKind::Float]).map(|v| v.as_raw_str())
}
pub fn as_number_str(self) -> Result<&'text str, JsonParseError> {
self.expect([JsonValueKind::Integer, JsonValueKind::Float])
.map(|v| v.as_raw_str())
}
pub fn as_string_str(self) -> Result<&'text str, JsonParseError> {
self.expect([JsonValueKind::String]).and_then(|v| {
if v.entry().escaped {
Err(v.invalid("string requires unescaping"))
} else {
let raw = v.as_raw_str();
Ok(&raw[1..raw.len() - 1])
}
})
}
pub fn to_unquoted_string_str(self) -> Result<Cow<'text, str>, JsonParseError> {
self.expect([JsonValueKind::String]).map(|v| v.unquote())
}
pub fn to_array(self) -> Result<impl Iterator<Item = Self>, JsonParseError> {
self.expect([JsonValueKind::Array]).map(Children::new)
}
pub fn to_object(self) -> Result<impl Iterator<Item = (Self, Self)>, JsonParseError> {
self.expect([JsonValueKind::Object])
.map(JsonKeyValuePairs::new)
}
pub fn to_member<'a>(
self,
name: &'a str,
) -> Result<RawJsonMember<'text, 'raw, 'a>, JsonParseError> {
let member = self.find_member_by_name(name)?;
Ok(RawJsonMember {
object: self,
name,
member,
})
}
pub fn to_path_member<'a>(
self,
path: &'a [&str],
) -> Result<RawJsonMember<'text, 'raw, 'a>, JsonParseError> {
let (last, parents) = path
.split_last()
.ok_or_else(|| self.invalid("path must not be empty"))?;
let mut current = self;
for name in parents {
current = current.to_member(name)?.required()?;
}
current.to_member(last)
}
pub fn map<F, T>(self, f: F) -> Result<T, JsonParseError>
where
F: FnOnce(RawJsonValue<'text, 'raw>) -> Result<T, JsonParseError>,
{
f(self)
}
pub fn invalid<E>(self, error: E) -> JsonParseError
where
E: Into<Box<dyn Send + Sync + core::error::Error>>,
{
JsonParseError::invalid_value(self, error)
}
fn unquote(self) -> Cow<'text, str> {
debug_assert!(self.kind().is_string());
let content = &self.as_raw_str()[1..self.as_raw_str().len() - 1];
if !self.entry().escaped {
return Cow::Borrowed(content);
}
let mut unescaped = String::with_capacity(content.len());
let mut chars = content.chars();
while let Some(c) = chars.next() {
match c {
'\\' => {
let c = chars.next().expect("infallible");
match c {
'\\' | '/' | '"' => unescaped.push(c),
'n' => unescaped.push('\n'),
't' => unescaped.push('\t'),
'r' => unescaped.push('\r'),
'b' => unescaped.push('\u{8}'),
'f' => unescaped.push('\u{c}'),
'u' => {
let c = core::str::from_utf8(&[
chars.next().expect("infallible") as u8,
chars.next().expect("infallible") as u8,
chars.next().expect("infallible") as u8,
chars.next().expect("infallible") as u8,
])
.ok()
.and_then(|code| u32::from_str_radix(code, 16).ok())
.and_then(char::from_u32)
.expect("infallible");
unescaped.push(c);
}
_ => unreachable!(),
}
}
_ => unescaped.push(c),
}
}
Cow::Owned(unescaped)
}
fn expect<const N: usize>(self, kinds: [JsonValueKind; N]) -> Result<Self, JsonParseError> {
if kinds.contains(&self.kind()) {
Ok(self)
} else {
Err(self.invalid(format!(
"expected {}, but found {:?}",
if kinds.len() == 1 {
format!("{:?}", kinds[0])
} else {
format!("one of {kinds:?}")
},
self.kind()
)))
}
}
fn find_member_by_name(self, name: &str) -> Result<Option<Self>, JsonParseError> {
Ok(self
.to_object()?
.find_map(|(k, v)| (k.unquote() == name).then_some(v)))
}
fn entry(&self) -> &JsonValueIndexEntry {
&self.json.values[self.index]
}
}
impl Display for RawJsonValue<'_, '_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", crate::Json(self))
}
}
impl DisplayJson for RawJsonValue<'_, '_> {
fn fmt(&self, f: &mut JsonFormatter<'_, '_>) -> core::fmt::Result {
match self.kind() {
JsonValueKind::Null
| JsonValueKind::Boolean
| JsonValueKind::Integer
| JsonValueKind::Float => write!(f.inner_mut(), "{}", self.as_raw_str()),
JsonValueKind::String => f.string(self.unquote()),
JsonValueKind::Array => f.array(|f| f.elements(self.to_array().expect("infallible"))),
JsonValueKind::Object => f.object(|f| {
f.members(
self.to_object()
.expect("infallible")
.map(|(k, v)| (k.unquote(), v)),
)
}),
}
}
}
#[derive(Debug)]
struct Children<'text, 'raw> {
value: RawJsonValue<'text, 'raw>,
end_index: usize,
}
impl<'text, 'raw> Children<'text, 'raw> {
fn new(mut value: RawJsonValue<'text, 'raw>) -> Self {
let end_index = value.entry().end_index;
value.index += 1;
Self { value, end_index }
}
}
impl<'text, 'raw> Iterator for Children<'text, 'raw> {
type Item = RawJsonValue<'text, 'raw>;
fn next(&mut self) -> Option<Self::Item> {
if self.value.index == self.end_index {
return None;
}
let value = self.value;
self.value.index = value.entry().end_index;
Some(value)
}
}
#[derive(Debug)]
struct JsonKeyValuePairs<'text, 'raw> {
inner: Children<'text, 'raw>,
}
impl<'text, 'raw> JsonKeyValuePairs<'text, 'raw> {
fn new(object: RawJsonValue<'text, 'raw>) -> Self {
Self {
inner: Children::new(object),
}
}
}
impl<'text, 'raw> Iterator for JsonKeyValuePairs<'text, 'raw> {
type Item = (RawJsonValue<'text, 'raw>, RawJsonValue<'text, 'raw>);
fn next(&mut self) -> Option<Self::Item> {
let key = self.inner.next()?;
let value = self.inner.next().expect("infallible");
Some((key, value))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawJsonMember<'text, 'raw, 'a> {
object: RawJsonValue<'text, 'raw>,
name: &'a str,
member: Option<RawJsonValue<'text, 'raw>>,
}
impl<'text, 'raw, 'a> RawJsonMember<'text, 'raw, 'a> {
pub fn required(self) -> Result<RawJsonValue<'text, 'raw>, JsonParseError> {
self.member.ok_or_else(|| {
self.object
.invalid(format!("required member '{}' is missing", self.name))
})
}
pub fn optional(self) -> Option<RawJsonValue<'text, 'raw>> {
self.member
}
#[deprecated(note = "use RawJsonMember::optional() instead")]
pub fn get(self) -> Option<RawJsonValue<'text, 'raw>> {
self.optional()
}
pub fn map<F, T>(self, f: F) -> Result<Option<T>, JsonParseError>
where
F: FnOnce(RawJsonValue<'text, 'raw>) -> Result<T, JsonParseError>,
{
self.member.map(f).transpose()
}
}
impl<'text, 'raw, 'a, T> TryFrom<RawJsonMember<'text, 'raw, 'a>> for Option<T>
where
T: TryFrom<RawJsonValue<'text, 'raw>, Error = JsonParseError>,
{
type Error = JsonParseError;
fn try_from(value: RawJsonMember<'text, 'raw, 'a>) -> Result<Self, Self::Error> {
value.member.map(T::try_from).transpose()
}
}