use serde::{
Serialize,
Serializer,
};
use crate::multi_values::MultiValuesRepr;
use crate::value::ValueRepr;
#[cfg(feature = "json")]
use crate::wire::JSON_NUMBER_TOKEN;
#[cfg(feature = "big-decimal")]
use crate::wire::{
MAX_BIG_DECIMAL_ABSOLUTE_SCALE,
is_valid_big_decimal_scale,
};
use crate::{
MultiValues,
Value,
ValueContainer,
};
use super::{
ValueWireEncodeError,
WireShapeRef,
};
#[must_use]
pub struct ValueWirePayloadRefV1<'a> {
shape: WireShapeRef<'a>,
}
impl<'a> ValueWirePayloadRefV1<'a> {
pub fn from_value(value: &'a Value) -> Result<Self, ValueWireEncodeError> {
validate_value(value)?;
Ok(Self {
shape: WireShapeRef::Scalar(value.into()),
})
}
pub fn from_values(
values: &'a MultiValues,
) -> Result<Self, ValueWireEncodeError> {
validate_values(values)?;
Ok(Self {
shape: WireShapeRef::Collection(values.into()),
})
}
pub fn from_container(
value: &'a ValueContainer,
) -> Result<Self, ValueWireEncodeError> {
match value {
ValueContainer::Scalar(value) => validate_value(value)?,
ValueContainer::Collection(values) => validate_values(values)?,
}
Ok(Self {
shape: value.into(),
})
}
pub(in crate::value_wire) fn shape(&self) -> WireShapeRef<'a> {
self.shape
}
}
pub(in crate::value_wire) fn validate_value(
value: &Value,
) -> Result<(), ValueWireEncodeError> {
#[cfg(feature = "big-decimal")]
if let ValueRepr::BigDecimal(value) = &value.repr {
validate_big_decimal_scale(value.as_bigint_and_exponent().1)?;
}
let non_finite = matches!(&value.repr, ValueRepr::Float32(value) if !value.is_finite())
|| matches!(&value.repr, ValueRepr::Float64(value) if !value.is_finite());
if non_finite {
return Err(ValueWireEncodeError::NonFiniteFloat {
data_type: value.data_type(),
});
}
#[cfg(feature = "json")]
if let ValueRepr::Json(value) = &value.repr {
validate_json_value(value)?;
}
Ok(())
}
pub(in crate::value_wire) fn validate_values(
values: &MultiValues,
) -> Result<(), ValueWireEncodeError> {
#[cfg(feature = "big-decimal")]
if let MultiValuesRepr::BigDecimal(values) = &values.repr {
for value in values {
validate_big_decimal_scale(value.as_bigint_and_exponent().1)?;
}
}
let non_finite = match &values.repr {
MultiValuesRepr::Float32(values) => {
values.iter().any(|value| !value.is_finite())
}
MultiValuesRepr::Float64(values) => {
values.iter().any(|value| !value.is_finite())
}
_ => false,
};
if non_finite {
return Err(ValueWireEncodeError::NonFiniteFloat {
data_type: values.data_type(),
});
}
#[cfg(feature = "json")]
if let MultiValuesRepr::Json(values) = &values.repr {
for value in values {
validate_json_value(value)?;
}
}
Ok(())
}
#[cfg(feature = "json")]
fn validate_json_value(
value: &serde_json::Value,
) -> Result<(), ValueWireEncodeError> {
match value {
serde_json::Value::Array(values) => {
for value in values {
validate_json_value(value)?;
}
}
serde_json::Value::Object(values) => {
if values.contains_key(JSON_NUMBER_TOKEN) {
return Err(ValueWireEncodeError::ReservedJsonObjectKey {
key: JSON_NUMBER_TOKEN,
});
}
for value in values.values() {
validate_json_value(value)?;
}
}
serde_json::Value::Null
| serde_json::Value::Bool(_)
| serde_json::Value::Number(_)
| serde_json::Value::String(_) => {}
}
Ok(())
}
#[cfg(feature = "big-decimal")]
fn validate_big_decimal_scale(scale: i64) -> Result<(), ValueWireEncodeError> {
if is_valid_big_decimal_scale(scale) {
return Ok(());
}
Err(ValueWireEncodeError::BigDecimalScaleTooLarge {
scale,
maximum_absolute_scale: MAX_BIG_DECIMAL_ABSOLUTE_SCALE,
})
}
impl<'a> TryFrom<&'a Value> for ValueWirePayloadRefV1<'a> {
type Error = ValueWireEncodeError;
fn try_from(value: &'a Value) -> Result<Self, Self::Error> {
Self::from_value(value)
}
}
impl<'a> TryFrom<&'a MultiValues> for ValueWirePayloadRefV1<'a> {
type Error = ValueWireEncodeError;
fn try_from(values: &'a MultiValues) -> Result<Self, Self::Error> {
Self::from_values(values)
}
}
impl<'a> TryFrom<&'a ValueContainer> for ValueWirePayloadRefV1<'a> {
type Error = ValueWireEncodeError;
fn try_from(value: &'a ValueContainer) -> Result<Self, Self::Error> {
Self::from_container(value)
}
}
impl Serialize for ValueWirePayloadRefV1<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.shape().serialize(serializer)
}
}