use std::borrow::Cow;
use std::fmt;
use std::marker::PhantomData;
use deser_core::de::{Deserialize, OwnedSink, Sink, SinkHandle};
use deser_core::ser::{Describe, Emit, Serialize};
use deser_core::{Atom, ContainerShape, Error, ErrorKind, State};
use deser_location::Locations;
use crate::Validator;
use crate::report::ReportHandle;
pub struct Validated<T, V = ()> {
value: Option<T>,
error: Option<Error>,
_validator: PhantomData<fn() -> V>,
}
impl<T, V: Validator<T>> Validated<T, V> {
pub fn new(value: T) -> Validated<T, V> {
let error = V::validate(&value).err().map(|x| x.into_error());
Validated {
value: Some(value),
error,
_validator: PhantomData,
}
}
}
impl<T, V> Validated<T, V> {
pub fn from_error(error: Error) -> Validated<T, V> {
Validated {
value: None,
error: Some(error),
_validator: PhantomData,
}
}
pub fn is_valid(&self) -> bool {
self.error.is_none()
}
pub fn value(&self) -> Option<&T> {
match self.error {
None => self.value.as_ref(),
Some(_) => None,
}
}
pub fn unchecked_value(&self) -> Option<&T> {
self.value.as_ref()
}
pub fn error(&self) -> Option<&Error> {
self.error.as_ref()
}
pub fn into_result(self) -> Result<T, Error> {
match (self.value, self.error) {
(Some(value), None) => Ok(value),
(_, Some(err)) => Err(err),
(None, None) => Err(Error::new(ErrorKind::InvalidState, "missing value")),
}
}
}
impl<T: fmt::Debug, V> fmt::Debug for Validated<T, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.error {
None => fmt::Debug::fmt(&self.value, f),
Some(ref err) => f
.debug_struct("Invalid")
.field("value", &self.value)
.field("error", &format_args!("{:#}", err))
.finish(),
}
}
}
impl<'de, T: Deserialize<'de>, V: Validator<T>> Deserialize<'de> for Validated<T, V> {
fn deserialize_into<'out>(
out: &'out mut Option<Self>,
state: &mut State,
) -> SinkHandle<'out, 'de> {
SinkHandle::arena(
ValidatedSink {
out,
sink: Some(OwnedSink::deserialize(state)),
error: None,
start: None,
outer: None,
},
state,
)
}
fn expecting() -> Cow<'static, str> {
T::expecting()
}
fn describe_type(d: &mut dyn Describe) {
T::describe_type(d)
}
fn initial_value() -> Option<Self> {
T::initial_value().map(Validated::new)
}
}
struct ValidatedSink<'a, 'de, T, V> {
out: &'a mut Option<Validated<T, V>>,
sink: Option<OwnedSink<'de, T>>,
error: Option<Error>,
start: Option<usize>,
outer: Option<bool>,
}
impl<'a, 'de, T, V> ValidatedSink<'a, 'de, T, V> {
fn sink(&mut self) -> Option<&mut (dyn Sink<'de> + '_)> {
self.sink.as_mut().map(|sink| sink.get_mut())
}
fn begin(&mut self, state: &mut State) -> Option<&mut (dyn Sink<'de> + '_)> {
if self.start.is_none() {
self.start = state.input_range().map(|range| range.start);
}
if self.outer.is_none() {
self.outer = Some(state.collect_errors());
state.set_collect_errors(true);
}
self.sink()
}
fn end(&mut self, state: &mut State) {
if let Some(outer) = self.outer.take() {
state.set_collect_errors(outer);
}
}
fn fail(&mut self, mut err: Error, state: &mut State) -> Result<(), Error> {
if state.discards_errors() || state.error_limit_reached() {
self.end(state);
return Err(err);
}
self.sink = None;
state.attach_error_context(&mut err);
self.error = Some(err);
Ok(())
}
fn check(&mut self, rv: Result<(), Error>, state: &mut State) -> Result<(), Error> {
match rv {
Ok(()) => Ok(()),
Err(err) => self.fail(err, state),
}
}
}
impl<'a, 'de, T: Send, V: Validator<T>> Sink<'de> for ValidatedSink<'a, 'de, T, V> {
fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
let rv = match self.begin(state) {
Some(sink) => sink.atom(atom, state),
None => Ok(()),
};
self.check(rv, state)
}
fn borrowed_atom(&mut self, atom: Atom<'de>, state: &mut State) -> Result<(), Error> {
let rv = match self.begin(state) {
Some(sink) => sink.borrowed_atom(atom, state),
None => Ok(()),
};
self.check(rv, state)
}
fn map(&mut self, state: &mut State) -> Result<(), Error> {
let rv = match self.begin(state) {
Some(sink) => sink.map(state),
None => Ok(()),
};
self.check(rv, state)
}
fn seq(&mut self, state: &mut State) -> Result<(), Error> {
let rv = match self.begin(state) {
Some(sink) => sink.seq(state),
None => Ok(()),
};
self.check(rv, state)
}
fn next_key(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
match self.sink() {
Some(sink) => sink.next_key(state),
None => Ok(SinkHandle::null()),
}
}
fn next_value(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
match self.sink() {
Some(sink) => sink.next_value(state),
None => Ok(SinkHandle::null()),
}
}
fn __private_key_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
match self.sink() {
Some(sink) => sink.__private_key_atom(atom, state),
None => Ok(()),
}
}
fn __private_value_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
match self.sink() {
Some(sink) => sink.__private_value_atom(atom, state),
None => Ok(()),
}
}
fn __private_borrowed_key_atom(
&mut self,
atom: Atom<'de>,
state: &mut State,
) -> Result<(), Error> {
match self.sink() {
Some(sink) => sink.__private_borrowed_key_atom(atom, state),
None => Ok(()),
}
}
fn __private_borrowed_value_atom(
&mut self,
atom: Atom<'de>,
state: &mut State,
) -> Result<(), Error> {
match self.sink() {
Some(sink) => sink.__private_borrowed_value_atom(atom, state),
None => Ok(()),
}
}
fn value_for_key(
&mut self,
key: &str,
state: &mut State,
) -> Result<Option<SinkHandle<'_, 'de>>, Error> {
match self.sink() {
Some(sink) => sink.value_for_key(key, state),
None => Ok(None),
}
}
fn recover(&mut self, err: Error, state: &mut State) -> Result<(), Error> {
let rv = match self.sink() {
Some(sink) => sink.recover(err, state),
None => Ok(()),
};
self.check(rv, state)
}
fn finish(&mut self, state: &mut State) -> Result<(), Error> {
let rv = match self.sink() {
Some(sink) => sink.finish(state),
None => Ok(()),
};
self.check(rv, state)?;
self.end(state);
let value = self.sink.as_mut().and_then(|sink| sink.take());
if let Some(ref value) = value
&& let Err(violation) = V::validate(value)
{
let mut err = violation.into_error();
if let Some(start) = self.start {
err.set_offset(start);
}
if state.discards_errors() {
return Err(err);
}
state.attach_error_context(&mut err);
self.error = Some(err);
}
if value.is_none() && self.error.is_none() {
return Ok(());
}
let error = self.error.take().map(|err| report_error(err, state));
*self.out = Some(Validated {
value,
error,
_validator: PhantomData,
});
Ok(())
}
fn expecting(&self) -> Cow<'_, str> {
match self.sink {
Some(ref sink) => sink.get().expecting(),
None => Cow::Borrowed("compatible type"),
}
}
}
fn report_error(mut err: Error, state: &mut State) -> Error {
if let Some(source_map) = Locations::source_map(state) {
err.resolve_position(source_map.source().as_bytes());
}
ReportHandle::report(&err, state);
err
}
impl<T: Serialize, V> Serialize for Validated<T, V> {
fn serialize<'a>(this: &'a Self, state: &mut State) -> Result<Emit<'a>, Error> {
match this.value {
Some(ref value) => T::serialize(value, state),
None => Ok(Emit::Atom(Atom::Null)),
}
}
fn finish(this: &Self, state: &mut State) -> Result<(), Error> {
match this.value {
Some(ref value) => T::finish(value, state),
None => Ok(()),
}
}
fn is_optional(this: &Self) -> bool {
match this.value {
Some(ref value) => T::is_optional(value),
None => true,
}
}
fn container_shape(this: &Self) -> ContainerShape {
match this.value {
Some(ref value) => T::container_shape(value),
None => ContainerShape::new(),
}
}
fn describe(this: &Self, d: &mut dyn Describe) {
if let Some(ref value) = this.value {
T::describe(value, d)
}
}
}