#[cfg(feature = "json")]
use std::io::Write;
#[cfg(feature = "chrono")]
use chrono::Datelike;
#[cfg(feature = "json")]
use qubit_budget::json::JsonEncodeLimits;
#[cfg(feature = "json")]
use qubit_budget::json::JsonEncodeSession;
#[cfg(feature = "json")]
use qubit_json::encode::JsonEncoder;
use serde::Serialize;
use serde::Serializer;
use super::ValueWireEncodeError;
#[cfg(feature = "json")]
use super::ValueWireEncodePreflight;
use super::WireShapeRef;
use super::internal::WireSourceRef;
use crate::MultiValues;
use crate::Value;
use crate::ValueContainer;
use crate::multi_values::MultiValuesRepr;
use crate::value::ValueRepr;
#[cfg(feature = "big-decimal")]
use crate::wire::MAX_BIG_DECIMAL_ABSOLUTE_SCALE;
#[cfg(feature = "big-decimal")]
use crate::wire::is_valid_big_decimal_scale;
#[cfg(feature = "json")]
use crate::wire::json::validate_numbers;
#[cfg(feature = "chrono")]
use crate::wire::validate_instant_year;
#[must_use]
pub struct ValueWirePayloadRefV1<'a> {
source: WireSourceRef<'a>,
}
impl<'a> ValueWirePayloadRefV1<'a> {
pub fn from_value(value: &'a Value) -> Result<Self, ValueWireEncodeError> {
validate_value(value)?;
Ok(Self {
source: WireSourceRef::Scalar(value),
})
}
pub fn from_values(values: &'a MultiValues) -> Result<Self, ValueWireEncodeError> {
validate_values(values)?;
Ok(Self {
source: WireSourceRef::Collection(values),
})
}
#[inline]
pub fn from_container(value: &'a ValueContainer) -> Result<Self, ValueWireEncodeError> {
match value {
ValueContainer::Scalar(value) => Self::from_value(value),
ValueContainer::Collection(values) => Self::from_values(values),
}
}
#[cfg(feature = "json")]
#[inline(always)]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
pub fn to_json_vec(&self) -> Result<Vec<u8>, ValueWireEncodeError> {
self.to_json_vec_with_limits(super::default_json_encode_limits())
}
#[cfg(feature = "json")]
#[inline]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
pub fn to_json_vec_with_limits(
&self,
limits: JsonEncodeLimits,
) -> Result<Vec<u8>, ValueWireEncodeError> {
self.check_encode_preflight(limits)?;
let session = JsonEncodeSession::from_limits(limits);
JsonEncoder::new(session)
.to_vec(self)
.map_err(ValueWireEncodeError::from)
}
#[cfg(feature = "json")]
#[inline(always)]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
pub fn to_json_writer<W>(&self, writer: W) -> Result<(), ValueWireEncodeError>
where
W: Write,
{
self.to_json_writer_with_limits(writer, super::default_json_encode_limits())
}
#[cfg(feature = "json")]
#[inline]
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
pub fn to_json_writer_with_limits<W>(
&self,
mut writer: W,
limits: JsonEncodeLimits,
) -> Result<(), ValueWireEncodeError>
where
W: Write,
{
self.check_encode_preflight(limits)?;
let session = JsonEncodeSession::from_limits(limits);
JsonEncoder::new(session)
.write_buffered(&mut writer, self)
.map_err(ValueWireEncodeError::from)
}
#[must_use]
#[inline(always)]
pub(in crate::value_wire) fn shape(&self) -> WireShapeRef<'a> {
match self.source {
WireSourceRef::Scalar(value) => WireShapeRef::Scalar(value.into()),
WireSourceRef::Collection(values) => WireShapeRef::Collection(values.into()),
}
}
#[cfg(feature = "json")]
pub(in crate::value_wire) fn check_encode_preflight(
&self,
limits: JsonEncodeLimits,
) -> Result<(), ValueWireEncodeError> {
let mut checker = ValueWireEncodePreflight::new(limits);
match self.source {
WireSourceRef::Scalar(value) => checker.check_value(value),
WireSourceRef::Collection(values) => checker.check_values(values),
}
.map_err(ValueWireEncodeError::from)
}
}
pub(in crate::value_wire) fn validate_value(value: &Value) -> Result<(), ValueWireEncodeError> {
#[cfg(feature = "json")]
if let ValueRepr::Json(value) = &value.repr {
validate_numbers(value)?;
}
#[cfg(feature = "chrono")]
if let ValueRepr::Instant(value) = &value.repr {
validate_instant_year(value.year())?;
}
#[cfg(feature = "big-decimal")]
if let ValueRepr::BigDecimal(value) = &value.repr {
validate_big_decimal_scale(value.as_bigint_and_scale().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(),
});
}
Ok(())
}
pub(in crate::value_wire) fn validate_values(
values: &MultiValues,
) -> Result<(), ValueWireEncodeError> {
#[cfg(feature = "json")]
if let MultiValuesRepr::Json(values) = &values.repr {
for value in values {
validate_numbers(value)?;
}
}
#[cfg(feature = "chrono")]
if let MultiValuesRepr::Instant(values) = &values.repr {
for value in values {
validate_instant_year(value.year())?;
}
}
#[cfg(feature = "big-decimal")]
if let MultiValuesRepr::BigDecimal(values) = &values.repr {
for value in values {
validate_big_decimal_scale(value.as_bigint_and_scale().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(),
});
}
Ok(())
}
#[cfg(feature = "big-decimal")]
#[inline]
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;
#[inline]
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;
#[inline]
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;
#[inline]
fn try_from(value: &'a ValueContainer) -> Result<Self, Self::Error> {
Self::from_container(value)
}
}
impl Serialize for ValueWirePayloadRefV1<'_> {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.shape().serialize(serializer)
}
}