#[cfg(feature = "converter")]
use qubit_datatype::ConversionLimits;
#[cfg(feature = "converter")]
use qubit_datatype::ConversionPolicy;
#[cfg(feature = "converter")]
use qubit_datatype::ConversionSession;
#[cfg(feature = "converter")]
use qubit_datatype::DataConversionTarget;
use qubit_datatype::DataType;
#[cfg(feature = "converter")]
use qubit_datatype::ScalarStringDataConverters;
use crate::MultiValues;
use crate::StrictValueRead;
use crate::Value;
use crate::ValueError;
use crate::ValueResult;
use crate::multi_values::MultiValuesRepr;
#[cfg(feature = "converter")]
use crate::value::ValueRef;
use crate::value::ValueRepr;
#[must_use]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ValueContainer {
Scalar(
Value,
),
Collection(
MultiValues,
),
}
macro_rules! impl_value_container_from_table {
(
;
$(
(
[$($cfg:meta),*],
$variant:ident,
$type:ty,
$data_type:expr,
$materialization:ident,
$json_class:ident,
$number_projection:ident,
$value_doc:literal,
$multi_doc:literal
$(, $_wire:tt)*
)
),+ $(,)?
) => {
$(
$(#[$cfg])*
impl From<$type> for ValueContainer {
#[inline(always)]
fn from(value: $type) -> Self {
Self::Scalar(Value::$variant(value))
}
}
$(#[$cfg])*
impl From<Vec<$type>> for ValueContainer {
#[inline(always)]
fn from(values: Vec<$type>) -> Self {
Self::Collection(MultiValues::$variant(values))
}
}
$(#[$cfg])*
impl From<&[$type]> for ValueContainer {
#[inline]
fn from(values: &[$type]) -> Self {
Self::Collection(MultiValues::$variant(values.to_vec()))
}
}
$(#[$cfg])*
impl From<&Vec<$type>> for ValueContainer {
#[inline]
fn from(values: &Vec<$type>) -> Self {
Self::Collection(MultiValues::$variant(values.clone()))
}
}
$(#[$cfg])*
impl<const N: usize> From<[$type; N]> for ValueContainer {
#[inline]
fn from(values: [$type; N]) -> Self {
Self::Collection(MultiValues::$variant(Vec::from(values)))
}
}
$(#[$cfg])*
impl<const N: usize> From<&[$type; N]> for ValueContainer {
#[inline]
fn from(values: &[$type; N]) -> Self {
Self::Collection(MultiValues::$variant(values.to_vec()))
}
}
)+
};
}
for_each_value_type!(impl_value_container_from_table);
macro_rules! value_container_pair_match {
($first:expr, $second:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
match ($first.repr, $second.repr) {
$(
$(#[$cfg])*
(ValueRepr::$variant(first), ValueRepr::$variant(second)) => {
MultiValues::$variant(vec![
value_storage_into_multi!($variant, first),
value_storage_into_multi!($variant, second),
])
}
)+
$(
$(#[$cfg])*
(ValueRepr::Unset(_), ValueRepr::$variant(second)) => {
MultiValues::$variant(vec![value_storage_into_multi!($variant, second)])
}
)+
_ => unreachable!(),
}
};
}
macro_rules! value_container_push_match {
($collection:expr, $value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
match (&mut $collection.repr, $value.repr) {
$(
$(#[$cfg])*
(MultiValuesRepr::$variant(values), ValueRepr::$variant(value)) => {
values.push(value_storage_into_multi!($variant, value))
},
)+
$(
$(#[$cfg])*
(slot @ MultiValuesRepr::Unset(_), ValueRepr::$variant(value)) => {
*slot = MultiValuesRepr::$variant(vec![value_storage_into_multi!($variant, value)]);
}
)+
_ => unreachable!(),
}
};
}
impl From<&str> for ValueContainer {
#[inline]
fn from(value: &str) -> Self {
Self::Scalar(Value::String(value.to_string()))
}
}
impl<'a> From<Vec<&'a str>> for ValueContainer {
#[inline]
fn from(values: Vec<&'a str>) -> Self {
Self::Collection(MultiValues::from(values))
}
}
impl<'a, 'b> From<&'a [&'b str]> for ValueContainer {
#[inline]
fn from(values: &'a [&'b str]) -> Self {
Self::Collection(MultiValues::from(values))
}
}
impl<'a, 'b> From<&'a Vec<&'b str>> for ValueContainer {
#[inline]
fn from(values: &'a Vec<&'b str>) -> Self {
Self::Collection(MultiValues::from(values))
}
}
impl<'a, const N: usize> From<[&'a str; N]> for ValueContainer {
#[inline]
fn from(values: [&'a str; N]) -> Self {
Self::Collection(MultiValues::from(values))
}
}
impl<'a, 'b, const N: usize> From<&'a [&'b str; N]> for ValueContainer {
#[inline]
fn from(values: &'a [&'b str; N]) -> Self {
Self::Collection(MultiValues::from(values))
}
}
impl From<Value> for ValueContainer {
#[inline(always)]
fn from(value: Value) -> Self {
Self::Scalar(value)
}
}
impl From<MultiValues> for ValueContainer {
#[inline(always)]
fn from(values: MultiValues) -> Self {
Self::Collection(values)
}
}
impl ValueContainer {
#[must_use = "the borrowed first-value result should be handled"]
#[inline(always)]
pub fn get_first_ref<'a, T: ?Sized>(&'a self) -> ValueResult<&'a T>
where
&'a T: TryFrom<&'a Value, Error = ValueError> + TryFrom<&'a MultiValues, Error = ValueError>,
{
match self {
Self::Scalar(value) => <&'a T>::try_from(value),
Self::Collection(values) => <&'a T>::try_from(values),
}
}
#[must_use = "the borrowed collection result should be handled"]
#[inline(always)]
pub fn get_slice<'a, T>(&'a self) -> ValueResult<&'a [T]>
where
&'a T: TryFrom<&'a Value, Error = ValueError>,
&'a [T]: TryFrom<&'a MultiValues, Error = ValueError>,
{
match self {
Self::Scalar(value) => value.get_ref().map(std::slice::from_ref),
Self::Collection(values) => values.get_slice(),
}
}
#[inline(always)]
pub const fn new_unset_scalar(data_type: DataType) -> Self {
Self::Scalar(Value::new_unset(data_type))
}
#[inline(always)]
pub const fn new_unset_collection(data_type: DataType) -> Self {
Self::Collection(MultiValues::new_unset(data_type))
}
#[must_use = "the runtime data type should be used"]
#[inline(always)]
pub fn data_type(&self) -> DataType {
match self {
Self::Scalar(value) => value.data_type(),
Self::Collection(values) => values.data_type(),
}
}
#[inline(always)]
#[must_use]
pub const fn is_scalar(&self) -> bool {
matches!(self, Self::Scalar(_))
}
#[must_use]
#[inline(always)]
pub const fn as_scalar(&self) -> Option<&Value> {
match self {
Self::Scalar(value) => Some(value),
Self::Collection(_) => None,
}
}
#[inline(always)]
pub fn into_scalar(self) -> Result<Value, Self> {
match self {
Self::Scalar(value) => Ok(value),
Self::Collection(_) => Err(self),
}
}
#[inline(always)]
#[must_use]
pub const fn is_collection(&self) -> bool {
matches!(self, Self::Collection(_))
}
#[must_use]
#[inline(always)]
pub const fn as_collection(&self) -> Option<&MultiValues> {
match self {
Self::Scalar(_) => None,
Self::Collection(values) => Some(values),
}
}
#[inline(always)]
pub fn into_collection(self) -> Result<MultiValues, Self> {
match self {
Self::Scalar(_) => Err(self),
Self::Collection(values) => Ok(values),
}
}
#[inline(always)]
#[must_use]
pub fn is_unset(&self) -> bool {
match self {
Self::Scalar(value) => value.is_unset(),
Self::Collection(values) => values.is_unset(),
}
}
#[inline(always)]
#[must_use]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
match self {
Self::Scalar(value) => usize::from(!value.is_unset()),
Self::Collection(values) => values.len(),
}
}
#[inline(always)]
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[must_use = "the strict first-value result should be handled"]
#[inline(always)]
pub fn get_first<T>(&self) -> ValueResult<T>
where
T: StrictValueRead,
{
match self {
Self::Scalar(value) => T::read_scalar(value),
Self::Collection(values) => T::read_collection_first(values),
}
}
#[must_use = "the strict collection read result should be handled"]
#[inline(always)]
pub fn get_list<T>(&self) -> ValueResult<Vec<T>>
where
T: StrictValueRead,
{
match self {
Self::Scalar(value) => T::read_scalar(value).map(|item| vec![item]),
Self::Collection(values) => T::read_collection_list(values),
}
}
#[inline(always)]
pub fn set<S>(&mut self, value: S)
where
S: Into<Self>,
{
*self = value.into();
}
pub fn add<S>(&mut self, values: S) -> ValueResult<()>
where
S: Into<Self>,
{
let other = values.into();
let expected = self.data_type();
let actual = other.data_type();
if expected != actual {
return Err(ValueError::TypeMismatch { expected, actual });
}
if other.is_empty() {
return Ok(());
}
match other {
Self::Scalar(value) => {
self.add_scalar(value, expected);
Ok(())
}
Self::Collection(other) => match self {
Self::Scalar(value) => {
let value = std::mem::replace(value, Value::new_unset(expected));
let mut collection = MultiValues::from(value);
collection.add(other)?;
*self = Self::Collection(collection);
Ok(())
}
Self::Collection(collection) => collection.add(other),
},
}
}
#[inline(always)]
pub fn unset(&mut self) {
match self {
Self::Scalar(value) => value.unset(),
Self::Collection(values) => values.unset(),
}
}
#[cfg(feature = "converter")]
#[inline(always)]
pub fn to_first<T>(&self) -> ValueResult<T>
where
T: DataConversionTarget,
{
self.to_first_with(ConversionPolicy::default_ref(), ConversionLimits::default_ref())
}
#[cfg(feature = "converter")]
#[inline(always)]
pub fn to_first_with<T>(&self, policy: &ConversionPolicy, limits: &ConversionLimits) -> ValueResult<T>
where
T: DataConversionTarget,
{
match self {
Self::Scalar(value) => value.to_with(policy, limits),
Self::Collection(values) => values.to_first_with(policy, limits),
}
}
#[cfg(feature = "converter")]
#[inline(always)]
pub fn to_first_in<T>(&self, session: &mut ConversionSession<'_>) -> ValueResult<T>
where
T: DataConversionTarget,
{
match self {
Self::Scalar(value) => value.to_in(session),
Self::Collection(values) => values.to_first_in(session),
}
}
#[cfg(feature = "converter")]
#[inline(always)]
pub fn to_list<T>(&self) -> ValueResult<Vec<T>>
where
T: DataConversionTarget,
{
self.to_list_with(ConversionPolicy::default_ref(), ConversionLimits::default_ref())
}
#[cfg(feature = "converter")]
pub fn to_list_with<T>(&self, policy: &ConversionPolicy, limits: &ConversionLimits) -> ValueResult<Vec<T>>
where
T: DataConversionTarget,
{
match self {
Self::Scalar(value) => match value.view() {
ValueRef::String(value) => ScalarStringDataConverters::from(value)
.to_vec_with(policy, limits)
.map_err(ValueError::from),
_ => value.to_with(policy, limits).map(|value| vec![value]),
},
Self::Collection(values) => values.to_list_with(policy, limits),
}
}
#[cfg(feature = "converter")]
pub fn to_list_in<T>(&self, session: &mut ConversionSession<'_>) -> ValueResult<Vec<T>>
where
T: DataConversionTarget,
{
match self {
Self::Scalar(value) => match value.view() {
ValueRef::String(value) => ScalarStringDataConverters::from(value)
.to_vec_in(session)
.map_err(ValueError::from),
_ => value.to_in(session).map(|value| vec![value]),
},
Self::Collection(values) => values.to_list_in(session),
}
}
#[inline]
fn add_scalar(&mut self, value: Value, data_type: DataType) {
match self {
Self::Scalar(current) => {
let current = std::mem::replace(current, Value::new_unset(data_type));
let collection = for_each_value_type!(value_container_pair_match, current, value);
*self = Self::Collection(collection);
}
Self::Collection(collection) => {
for_each_value_type!(value_container_push_match, collection, value);
}
}
}
}
#[cfg(all(feature = "converter", feature = "json"))]
impl ValueContainer {
#[inline(always)]
pub fn to_json_value(&self) -> ValueResult<serde_json::Value> {
self.to_json_value_with(ConversionPolicy::default_ref(), ConversionLimits::default_ref())
}
#[inline(always)]
pub fn to_json_value_with(
&self,
policy: &ConversionPolicy,
limits: &ConversionLimits,
) -> ValueResult<serde_json::Value> {
crate::json::value_container_to_json_value_with(self, policy, limits)
}
}