use crate::budget::EnforcingPolicy;
use crate::de::{Error, Ev, Events, Options};
#[cfg(feature = "garde")]
use crate::de_error::collect_garde_issues;
#[cfg(feature = "validator")]
use crate::de_error::collect_validator_issues;
use crate::de_error::redact_issue;
use crate::live_events::LiveEvents;
use crate::maybe_with_snippet_from_events;
use crate::parse_scalars::scalar_is_nullish;
use crate::properties_redaction::with_interp_redaction_scope;
use crate::ReaderSnippetContext;
use serde::de::DeserializeOwned;
use std::io::Read;
#[cfg(feature = "garde")]
use garde::Validate;
#[cfg(feature = "validator")]
use validator::Validate as ValidatorValidate;
#[cfg(feature = "garde")]
#[allow(deprecated)]
fn from_str_with_options_and_path_recorder_garde_valid<'de, T, F>(
input: &'de str,
options: Options,
validate: F,
) -> Result<(T, LiveEvents<'de>), Error>
where
T: DeserializeOwned + garde::Validate,
F: FnOnce(&T) -> Result<(), garde::Report>,
{
let input = if let Some(rest) = input.strip_prefix('\u{FEFF}') {
rest
} else {
input
};
let with_snippet = options.with_snippet;
let crop_radius = options.crop_radius;
let cfg = crate::de::Cfg::from_options(&options);
let mut src = LiveEvents::from_str(input, options, false);
let mut recorder = crate::path_map::PathRecorder::new();
let value_res = crate::anchor_store::with_document_scope(|| {
with_interp_redaction_scope(|| {
let value = crate::de::with_root_redaction(
crate::de::YamlDeserializer::new_with_path_recorder(&mut src, cfg, &mut recorder),
|de| T::deserialize(de),
)?;
validate(&value).map_err(|report| Error::ValidationError {
issues: collect_garde_issues(&report)
.into_iter()
.map(redact_issue)
.collect(),
locations: recorder.map.clone(),
})?;
Ok(value)
})
});
let value = match value_res {
Ok(v) => v,
Err(e) => {
if src.synthesized_null_emitted() {
let err = Error::eof().with_location(src.last_location());
return Err(maybe_with_snippet_from_events(
err,
input,
&src,
with_snippet,
crop_radius,
));
} else {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
}
};
match src.peek() {
Ok(Some(_)) => {
let err = Error::multiple_documents("use from_multiple or from_multiple_with_options")
.with_location(src.last_location());
return Err(maybe_with_snippet_from_events(
err,
input,
&src,
with_snippet,
crop_radius,
));
}
Ok(None) => {}
Err(e) => {
if !src.seen_doc_end() {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
}
}
Ok((value, src))
}
#[cfg(feature = "validator")]
#[allow(deprecated)]
fn from_str_with_options_and_path_recorder_validator_valid<'de, T>(
input: &'de str,
options: Options,
) -> Result<(T, LiveEvents<'de>), Error>
where
T: DeserializeOwned + ValidatorValidate,
{
let input = if let Some(rest) = input.strip_prefix('\u{FEFF}') {
rest
} else {
input
};
let with_snippet = options.with_snippet;
let crop_radius = options.crop_radius;
let cfg = crate::de::Cfg::from_options(&options);
let mut src = LiveEvents::from_str(input, options, false);
let mut recorder = crate::path_map::PathRecorder::new();
let value_res = crate::anchor_store::with_document_scope(|| {
with_interp_redaction_scope(|| {
let value = crate::de::with_root_redaction(
crate::de::YamlDeserializer::new_with_path_recorder(&mut src, cfg, &mut recorder),
|de| T::deserialize(de),
)?;
ValidatorValidate::validate(&value).map_err(|errors| Error::ValidatorError {
issues: collect_validator_issues(&errors)
.into_iter()
.map(redact_issue)
.collect(),
locations: recorder.map.clone(),
})?;
Ok(value)
})
});
let value = match value_res {
Ok(v) => v,
Err(e) => {
if src.synthesized_null_emitted() {
let err = Error::eof().with_location(src.last_location());
return Err(maybe_with_snippet_from_events(
err,
input,
&src,
with_snippet,
crop_radius,
));
} else {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
}
};
match src.peek() {
Ok(Some(_)) => {
let err = Error::multiple_documents("use from_multiple or from_multiple_with_options")
.with_location(src.last_location());
return Err(maybe_with_snippet_from_events(
err,
input,
&src,
with_snippet,
crop_radius,
));
}
Ok(None) => {}
Err(e) => {
if !src.seen_doc_end() {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
}
}
Ok((value, src))
}
#[cfg(feature = "garde")]
pub fn from_str_valid<T>(input: &str) -> Result<T, Error>
where
T: DeserializeOwned + garde::Validate,
<T as garde::Validate>::Context: Default,
{
from_str_with_options_valid(input, Options::default())
}
#[cfg(feature = "garde")]
pub fn from_str_with_options_valid<T>(input: &str, options: Options) -> Result<T, Error>
where
T: DeserializeOwned + garde::Validate,
<T as garde::Validate>::Context: Default,
{
let with_snippet = options.with_snippet;
let crop_radius = options.crop_radius;
let (v, mut src) =
from_str_with_options_and_path_recorder_garde_valid::<T, _>(input, options, |value| {
Validate::validate(value)
})?;
if let Err(e) = src.finish() {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
Ok(v)
}
#[cfg(feature = "garde")]
pub fn from_str_with_options_context_valid<T>(
input: &str,
options: Options,
context: &<T as garde::Validate>::Context,
) -> Result<T, Error>
where
T: DeserializeOwned + garde::Validate,
{
let with_snippet = options.with_snippet;
let crop_radius = options.crop_radius;
let (v, mut src) =
from_str_with_options_and_path_recorder_garde_valid::<T, _>(input, options, |value| {
Validate::validate_with(value, context)
})?;
if let Err(e) = src.finish() {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
Ok(v)
}
#[cfg(feature = "garde")]
pub fn from_multiple_valid<T: DeserializeOwned + garde::Validate>(
input: &str,
) -> Result<Vec<T>, Error>
where
<T as garde::Validate>::Context: Default,
{
from_multiple_with_options_valid(input, Options::default())
}
#[cfg(feature = "garde")]
#[allow(deprecated)]
pub fn from_multiple_with_options_valid<T>(input: &str, options: Options) -> Result<Vec<T>, Error>
where
T: DeserializeOwned + garde::Validate,
<T as garde::Validate>::Context: Default,
{
let with_snippet = options.with_snippet;
let crop_radius = options.crop_radius;
let cfg = crate::de::Cfg::from_options(&options);
let mut src = LiveEvents::from_str(input, options, false);
let mut values = Vec::new();
let mut validation_errors: Vec<Error> = Vec::new();
loop {
match src.peek()? {
Some(Ev::Scalar {
value: s,
style,
tag,
..
}) if *tag == crate::tags::SfTag::Null
|| (*tag != crate::tags::SfTag::String && scalar_is_nullish(s, style)) =>
{
let _ = src.next()?; continue;
}
Some(_) => {
let mut recorder = crate::path_map::PathRecorder::new();
let value_res = crate::anchor_store::with_document_scope(|| {
with_interp_redaction_scope(|| {
let value = crate::de::with_root_redaction(
crate::de::YamlDeserializer::new_with_path_recorder(
&mut src,
cfg,
&mut recorder,
),
|de| T::deserialize(de),
)?;
Validate::validate(&value).map_err(|report| Error::ValidationError {
issues: collect_garde_issues(&report)
.into_iter()
.map(redact_issue)
.collect(),
locations: recorder.map.clone(),
})?;
Ok(value)
})
});
let value = match value_res {
Ok(v) => v,
Err(Error::ValidationError { issues, locations }) => {
let err = Error::ValidationError { issues, locations };
validation_errors.push(maybe_with_snippet_from_events(
err,
input,
&src,
with_snippet,
crop_radius,
));
continue;
}
Err(e) => {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
};
values.push(value);
}
None => break,
}
}
if let Err(e) = src.finish() {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
if validation_errors.is_empty() {
Ok(values)
} else {
Err(Error::ValidationErrors {
errors: validation_errors,
})
}
}
#[cfg(feature = "garde")]
pub fn from_slice_valid<T: DeserializeOwned + garde::Validate>(bytes: &[u8]) -> Result<T, Error>
where
<T as garde::Validate>::Context: Default,
{
from_slice_with_options_valid(bytes, Options::default())
}
#[cfg(feature = "garde")]
pub fn from_slice_with_options_valid<T: DeserializeOwned + garde::Validate>(
bytes: &[u8],
options: Options,
) -> Result<T, Error>
where
<T as garde::Validate>::Context: Default,
{
let s = std::str::from_utf8(bytes).map_err(|_| Error::InvalidUtf8Input)?;
from_str_with_options_valid(s, options)
}
#[cfg(feature = "garde")]
pub fn from_slice_multiple_with_options_valid<T>(
bytes: &[u8],
options: Options,
) -> Result<Vec<T>, Error>
where
T: DeserializeOwned + garde::Validate,
<T as garde::Validate>::Context: Default,
{
let s = std::str::from_utf8(bytes).map_err(|_| Error::InvalidUtf8Input)?;
from_multiple_with_options_valid(s, options)
}
#[cfg(feature = "garde")]
pub fn from_reader_valid<R: std::io::Read, T>(reader: R) -> Result<T, Error>
where
T: DeserializeOwned + garde::Validate,
<T as garde::Validate>::Context: Default,
{
from_reader_with_options_valid(reader, Options::default())
}
#[cfg(feature = "garde")]
#[allow(deprecated)]
pub fn from_reader_with_options_valid<R: std::io::Read, T>(
reader: R,
options: Options,
) -> Result<T, Error>
where
T: DeserializeOwned + garde::Validate,
<T as garde::Validate>::Context: Default,
{
let cfg = crate::de::Cfg::from_options(&options);
let (snippet_ctx, ring_handle) =
ReaderSnippetContext::new(reader, options.with_snippet, options.crop_radius);
let mut src = LiveEvents::from_reader(ring_handle, options, false, EnforcingPolicy::AllContent);
let mut recorder = crate::path_map::PathRecorder::new();
let value_res = crate::anchor_store::with_document_scope(|| {
with_interp_redaction_scope(|| {
let value = crate::de::with_root_redaction(
crate::de::YamlDeserializer::new_with_path_recorder(&mut src, cfg, &mut recorder),
|de| T::deserialize(de),
)?;
Validate::validate(&value).map_err(|report| Error::ValidationError {
issues: collect_garde_issues(&report)
.into_iter()
.map(redact_issue)
.collect(),
locations: recorder.map.clone(),
})?;
Ok(value)
})
});
let value = match value_res {
Ok(v) => v,
Err(e) => {
if src.synthesized_null_emitted() {
return Err(snippet_ctx
.attach_snippet(Error::eof().with_location(src.last_location()), &src));
} else {
return Err(snippet_ctx.attach_snippet(e, &src));
}
}
};
match src.peek() {
Ok(Some(_)) => {
return Err(snippet_ctx.attach_snippet(
Error::multiple_documents(
"use read_valid or read_with_options_valid to obtain the iterator",
)
.with_location(src.last_location()),
&src,
));
}
Ok(None) => {}
Err(e) => {
if src.seen_doc_end() {
} else {
return Err(snippet_ctx.attach_snippet(e, &src));
}
}
}
if let Err(e) = src.finish() {
return Err(snippet_ctx.attach_snippet(e, &src));
}
Ok(value)
}
#[cfg(feature = "garde")]
pub fn read_valid<'a, R, T>(reader: &'a mut R) -> impl Iterator<Item = Result<T, Error>> + 'a
where
R: Read + 'a,
T: DeserializeOwned + garde::Validate + 'a,
<T as garde::Validate>::Context: Default,
{
read_with_options_valid(reader, Default::default())
}
#[cfg(feature = "garde")]
#[allow(deprecated)]
pub fn read_with_options_valid<'a, R, T>(
reader: &'a mut R,
options: Options,
) -> impl Iterator<Item = Result<T, Error>> + 'a
where
R: Read + 'a,
T: DeserializeOwned + garde::Validate + 'a,
<T as garde::Validate>::Context: Default,
{
struct ReadValidIter<'a, R, T> {
snippet_ctx: ReaderSnippetContext<&'a mut R>,
src: LiveEvents<'a>, cfg: crate::de::Cfg,
finished: bool,
_marker: std::marker::PhantomData<T>,
}
impl<'a, R, T> Iterator for ReadValidIter<'a, R, T>
where
R: Read + 'a,
T: DeserializeOwned + garde::Validate + 'a,
<T as garde::Validate>::Context: Default,
{
type Item = Result<T, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None;
}
loop {
match self.src.peek() {
Ok(Some(Ev::Scalar { value, style, .. }))
if scalar_is_nullish(value, style) =>
{
let _ = self.src.next();
continue;
}
Ok(Some(_)) => {
let mut recorder = crate::path_map::PathRecorder::new();
let value_res = crate::anchor_store::with_document_scope(|| {
with_interp_redaction_scope(|| {
let value = T::deserialize(
crate::de::YamlDeserializer::new_with_path_recorder(
&mut self.src,
self.cfg,
&mut recorder,
),
)?;
Validate::validate(&value).map_err(|report| {
Error::ValidationError {
issues: collect_garde_issues(&report)
.into_iter()
.map(redact_issue)
.collect(),
locations: recorder.map.clone(),
}
})?;
Ok(value)
})
});
let value = match value_res {
Ok(v) => v,
Err(e) => {
let err = self.snippet_ctx.attach_snippet(e, &self.src);
if !self.src.skip_to_next_document() {
self.finished = true;
}
return Some(Err(err));
}
};
return Some(Ok(value));
}
Ok(None) => {
self.finished = true;
if let Err(e) = self.src.finish() {
return Some(Err(self.snippet_ctx.attach_snippet(e, &self.src)));
}
return None;
}
Err(e) => {
self.finished = true;
let _ = self.src.finish();
return Some(Err(self.snippet_ctx.attach_snippet(e, &self.src)));
}
}
}
}
}
let cfg = crate::de::Cfg::from_options(&options);
let (snippet_ctx, ring_handle) =
ReaderSnippetContext::new(reader, options.with_snippet, options.crop_radius);
let src = LiveEvents::from_reader(ring_handle, options, false, EnforcingPolicy::PerDocument);
ReadValidIter::<R, T> {
snippet_ctx,
src,
cfg,
finished: false,
_marker: std::marker::PhantomData,
}
}
#[cfg(feature = "validator")]
pub fn from_str_validate<T>(input: &str) -> Result<T, Error>
where
T: DeserializeOwned + ValidatorValidate,
{
from_str_with_options_validate(input, Options::default())
}
#[cfg(feature = "validator")]
pub fn from_str_with_options_validate<T>(input: &str, options: Options) -> Result<T, Error>
where
T: DeserializeOwned + ValidatorValidate,
{
let with_snippet = options.with_snippet;
let crop_radius = options.crop_radius;
let (v, mut src) =
from_str_with_options_and_path_recorder_validator_valid::<T>(input, options)?;
if let Err(e) = src.finish() {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
Ok(v)
}
#[cfg(feature = "validator")]
pub fn from_multiple_validate<T: DeserializeOwned + ValidatorValidate>(
input: &str,
) -> Result<Vec<T>, Error> {
from_multiple_with_options_validate(input, Options::default())
}
#[cfg(feature = "validator")]
#[allow(deprecated)]
pub fn from_multiple_with_options_validate<T>(
input: &str,
options: Options,
) -> Result<Vec<T>, Error>
where
T: DeserializeOwned + ValidatorValidate,
{
let with_snippet = options.with_snippet;
let crop_radius = options.crop_radius;
let cfg = crate::de::Cfg::from_options(&options);
let mut src = LiveEvents::from_str(input, options, false);
let mut values = Vec::new();
let mut validation_errors: Vec<Error> = Vec::new();
loop {
match src.peek()? {
Some(Ev::Scalar {
value: s,
style,
tag,
..
}) if *tag == crate::tags::SfTag::Null
|| (*tag != crate::tags::SfTag::String && scalar_is_nullish(s, style)) =>
{
let _ = src.next()?; continue;
}
Some(_) => {
let mut recorder = crate::path_map::PathRecorder::new();
let value_res = crate::anchor_store::with_document_scope(|| {
with_interp_redaction_scope(|| {
let value = crate::de::with_root_redaction(
crate::de::YamlDeserializer::new_with_path_recorder(
&mut src,
cfg,
&mut recorder,
),
|de| T::deserialize(de),
)?;
ValidatorValidate::validate(&value).map_err(|errors| {
Error::ValidatorError {
issues: collect_validator_issues(&errors)
.into_iter()
.map(redact_issue)
.collect(),
locations: recorder.map.clone(),
}
})?;
Ok(value)
})
});
let value = match value_res {
Ok(v) => v,
Err(Error::ValidatorError { issues, locations }) => {
let err = Error::ValidatorError { issues, locations };
validation_errors.push(maybe_with_snippet_from_events(
err,
input,
&src,
with_snippet,
crop_radius,
));
continue;
}
Err(e) => {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
};
values.push(value);
}
None => break,
}
}
if let Err(e) = src.finish() {
return Err(maybe_with_snippet_from_events(
e,
input,
&src,
with_snippet,
crop_radius,
));
}
if validation_errors.is_empty() {
Ok(values)
} else {
Err(Error::ValidatorErrors {
errors: validation_errors,
})
}
}
#[cfg(feature = "validator")]
pub fn from_slice_validate<T: DeserializeOwned + ValidatorValidate>(
bytes: &[u8],
) -> Result<T, Error> {
from_slice_with_options_validate(bytes, Options::default())
}
#[cfg(feature = "validator")]
pub fn from_slice_with_options_validate<T: DeserializeOwned + ValidatorValidate>(
bytes: &[u8],
options: Options,
) -> Result<T, Error> {
let s = std::str::from_utf8(bytes).map_err(|_| Error::InvalidUtf8Input)?;
from_str_with_options_validate(s, options)
}
#[cfg(feature = "validator")]
pub fn from_slice_multiple_with_options_validate<T>(
bytes: &[u8],
options: Options,
) -> Result<Vec<T>, Error>
where
T: DeserializeOwned + ValidatorValidate,
{
let s = std::str::from_utf8(bytes).map_err(|_| Error::InvalidUtf8Input)?;
from_multiple_with_options_validate(s, options)
}
#[cfg(feature = "validator")]
pub fn from_reader_validate<R: std::io::Read, T>(reader: R) -> Result<T, Error>
where
T: DeserializeOwned + ValidatorValidate,
{
from_reader_with_options_validate(reader, Options::default())
}
#[cfg(feature = "validator")]
#[allow(deprecated)]
pub fn from_reader_with_options_validate<R: std::io::Read, T>(
reader: R,
options: Options,
) -> Result<T, Error>
where
T: DeserializeOwned + ValidatorValidate,
{
let cfg = crate::de::Cfg::from_options(&options);
let (snippet_ctx, ring_handle) =
ReaderSnippetContext::new(reader, options.with_snippet, options.crop_radius);
let mut src = LiveEvents::from_reader(ring_handle, options, false, EnforcingPolicy::AllContent);
let mut recorder = crate::path_map::PathRecorder::new();
let value_res = crate::anchor_store::with_document_scope(|| {
with_interp_redaction_scope(|| {
let value = crate::de::with_root_redaction(
crate::de::YamlDeserializer::new_with_path_recorder(&mut src, cfg, &mut recorder),
|de| T::deserialize(de),
)?;
ValidatorValidate::validate(&value).map_err(|errors| Error::ValidatorError {
issues: collect_validator_issues(&errors)
.into_iter()
.map(redact_issue)
.collect(),
locations: recorder.map.clone(),
})?;
Ok(value)
})
});
let value = match value_res {
Ok(v) => v,
Err(e) => {
if src.synthesized_null_emitted() {
return Err(snippet_ctx
.attach_snippet(Error::eof().with_location(src.last_location()), &src));
} else {
return Err(snippet_ctx.attach_snippet(e, &src));
}
}
};
match src.peek() {
Ok(Some(_)) => {
return Err(snippet_ctx.attach_snippet(
Error::multiple_documents(
"use read_validate or read_with_options_validate to obtain the iterator",
)
.with_location(src.last_location()),
&src,
));
}
Ok(None) => {}
Err(e) => {
if src.seen_doc_end() {
} else {
return Err(snippet_ctx.attach_snippet(e, &src));
}
}
}
if let Err(e) = src.finish() {
return Err(snippet_ctx.attach_snippet(e, &src));
}
Ok(value)
}
#[cfg(feature = "validator")]
pub fn read_validate<'a, R, T>(reader: &'a mut R) -> impl Iterator<Item = Result<T, Error>> + 'a
where
R: Read + 'a,
T: DeserializeOwned + ValidatorValidate + 'a,
{
read_with_options_validate(reader, Default::default())
}
#[cfg(feature = "validator")]
#[allow(deprecated)]
pub fn read_with_options_validate<'a, R, T>(
reader: &'a mut R,
options: Options,
) -> impl Iterator<Item = Result<T, Error>> + 'a
where
R: Read + 'a,
T: DeserializeOwned + ValidatorValidate + 'a,
{
struct ReadValidateIter<'a, R, T> {
snippet_ctx: ReaderSnippetContext<&'a mut R>,
src: LiveEvents<'a>, cfg: crate::de::Cfg,
finished: bool,
_marker: std::marker::PhantomData<T>,
}
impl<'a, R, T> Iterator for ReadValidateIter<'a, R, T>
where
R: Read + 'a,
T: DeserializeOwned + ValidatorValidate + 'a,
{
type Item = Result<T, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None;
}
loop {
match self.src.peek() {
Ok(Some(Ev::Scalar { value, style, .. }))
if scalar_is_nullish(value, style) =>
{
let _ = self.src.next();
continue;
}
Ok(Some(_)) => {
let mut recorder = crate::path_map::PathRecorder::new();
let value_res = crate::anchor_store::with_document_scope(|| {
with_interp_redaction_scope(|| {
let value = T::deserialize(
crate::de::YamlDeserializer::new_with_path_recorder(
&mut self.src,
self.cfg,
&mut recorder,
),
)?;
ValidatorValidate::validate(&value).map_err(|errors| {
Error::ValidatorError {
issues: collect_validator_issues(&errors)
.into_iter()
.map(redact_issue)
.collect(),
locations: recorder.map.clone(),
}
})?;
Ok(value)
})
});
let value = match value_res {
Ok(v) => v,
Err(e) => {
let err = self.snippet_ctx.attach_snippet(e, &self.src);
if !self.src.skip_to_next_document() {
self.finished = true;
}
return Some(Err(err));
}
};
return Some(Ok(value));
}
Ok(None) => {
self.finished = true;
if let Err(e) = self.src.finish() {
return Some(Err(self.snippet_ctx.attach_snippet(e, &self.src)));
}
return None;
}
Err(e) => {
self.finished = true;
let _ = self.src.finish();
return Some(Err(self.snippet_ctx.attach_snippet(e, &self.src)));
}
}
}
}
}
let cfg = crate::de::Cfg::from_options(&options);
let (snippet_ctx, ring_handle) =
ReaderSnippetContext::new(reader, options.with_snippet, options.crop_radius);
let src = LiveEvents::from_reader(ring_handle, options, false, EnforcingPolicy::PerDocument);
ReadValidateIter::<R, T> {
snippet_ctx,
src,
cfg,
finished: false,
_marker: std::marker::PhantomData,
}
}