use crate::error::DeserializeSequenceError;
use crate::{DeserializeErrors, Key, Value};
use std::borrow::Cow;
use nonempty::NonEmpty;
use toml::de::DeValue;
use crate::Error;
pub fn value_type_description(value: &Value) -> Cow<'static, str> {
let value = value.as_ref();
if let Some(bool) = value.as_bool() {
bool.to_string().into()
} else if value.is_str() {
"string".into()
} else if value.is_integer() {
"int".into()
} else if value.is_float() {
"float".into()
} else if let Some(array) = value.as_array() {
let are_all_types_eq = array.iter().all(|value| {
Some(value_type_description(value)) == array.iter().next().map(value_type_description)
});
if are_all_types_eq && let Some(first) = array.iter().next() {
format!("list of {}", value_type_description(first)).into()
} else if array.is_empty() {
"empty list".into()
} else {
format!(
"tuple ({})",
array
.iter()
.map(value_type_description)
.collect::<Vec<_>>()
.join(", ")
)
.into()
}
} else if value.is_table() {
"table".into()
} else if value.is_datetime() {
"date".into()
} else {
"unknown".into()
}
}
#[allow(clippy::missing_errors_doc, reason = "explain later")]
#[allow(clippy::type_complexity, reason = "it is not complex")]
pub fn deserialize_sequence<'de, T, E: Error, Deserializer, Describer>(
value: Value<'de>,
deserializer: Deserializer,
describer: Describer,
) -> Result<Vec<T>, (Option<Vec<T>>, DeserializeSequenceError<E>)>
where
Deserializer: for<'a> Fn(Key<'a>, Value<'de>) -> Result<T, DeserializeErrors<T, NonEmpty<E>>>,
Describer: for<'a> Fn(&'a Value) -> String,
{
let span = value.span();
let details = describer(&value);
let DeValue::Array(array) = value.into_inner() else {
return Err((
None,
DeserializeSequenceError::NotList {
details,
span: span.into(),
},
));
};
let mut errs = vec![];
let mut ts = vec![];
for (i, value) in array.into_iter().enumerate() {
match deserializer(Key::Index(i), value) {
Ok(t) => {
ts.push(t);
}
Err(DeserializeErrors { recovered, errors }) => {
ts.extend(recovered);
errs.extend(errors);
}
}
}
if let Some(errors) = NonEmpty::from_vec(errs) {
Err((
Some(ts),
DeserializeSequenceError::InvalidSequence {
details,
span: span.into(),
errors,
},
))
} else {
Ok(ts)
}
}