#[cfg(feature = "json")]
use std::io::Write;
#[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;
use super::WireShapeRef;
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;
#[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() })
}
#[must_use]
#[inline(always)]
pub(in crate::value_wire) fn shape(&self) -> WireShapeRef<'a> {
self.shape
}
#[cfg(feature = "json")]
#[inline(always)]
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]
pub fn to_json_vec_with_limits(&self, limits: JsonEncodeLimits) -> Result<Vec<u8>, ValueWireEncodeError> {
let session = JsonEncodeSession::from_limits(limits);
JsonEncoder::new(session)
.to_vec(self)
.map_err(ValueWireEncodeError::from)
}
#[cfg(feature = "json")]
#[inline(always)]
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]
pub fn to_json_writer_with_limits<W>(&self, writer: W, limits: JsonEncodeLimits) -> Result<(), ValueWireEncodeError>
where
W: Write,
{
let session = JsonEncodeSession::from_limits(limits);
JsonEncoder::new(session)
.write_buffered(writer, self)
.map_err(ValueWireEncodeError::from)
}
}
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(),
});
}
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(),
});
}
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)
}
}