use qubit_datatype::DataType;
use std::fmt;
use super::multi_values_ref::MultiValuesRef;
macro_rules! define_multi_values_enum {
(
;
$(
(
[$($cfg:meta),*],
$variant:ident,
$type:ty,
$data_type:expr,
$materialization:ident,
$json_class:ident,
$number_projection:ident,
$value_doc:literal,
$multi_doc:literal
)
),+ $(,)?
) => {
#[derive(Debug, Clone)]
pub(crate) enum MultiValuesRepr {
Unset(
/// Declared element type retained while the collection is unset.
DataType,
),
$(
$(#[$cfg])*
#[doc = $multi_doc]
$variant(
#[doc = concat!("Stored ", $multi_doc, " payload.")]
Vec<$type>,
),
)+
}
};
}
for_each_value_type!(define_multi_values_enum);
#[must_use]
#[derive(Clone)]
pub struct MultiValues {
pub(crate) repr: MultiValuesRepr,
}
impl fmt::Debug for MultiValues {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.view().fmt(formatter)
}
}
macro_rules! impl_multi_values_constructors {
(
;
$(
(
[$($cfg:meta),*],
$variant:ident,
$type:ty,
$data_type:expr,
$materialization:ident,
$json_class:ident,
$number_projection:ident,
$value_doc:literal,
$multi_doc:literal
)
),+ $(,)?
) => {
impl MultiValues {
#[allow(non_snake_case)]
#[inline(always)]
pub const fn Unset(data_type: DataType) -> Self {
Self::new_unset(data_type)
}
#[inline(always)]
pub const fn new_unset(data_type: DataType) -> Self {
Self { repr: MultiValuesRepr::Unset(data_type) }
}
$(
$(#[$cfg])*
#[allow(non_snake_case)]
#[doc = concat!("Creates a collection of ", $multi_doc, ".")]
#[inline(always)]
pub fn $variant(values: Vec<$type>) -> Self {
Self { repr: MultiValuesRepr::$variant(values) }
}
)+
}
};
}
for_each_value_type!(impl_multi_values_constructors);
impl MultiValues {
#[inline(always)]
pub fn view(&self) -> MultiValuesRef<'_> {
match &self.repr {
MultiValuesRepr::Unset(data_type) => {
MultiValuesRef::Unset(*data_type)
}
MultiValuesRepr::Bool(values) => MultiValuesRef::Bool(values),
MultiValuesRepr::Char(values) => MultiValuesRef::Char(values),
MultiValuesRepr::Int8(values) => MultiValuesRef::Int8(values),
MultiValuesRepr::Int16(values) => MultiValuesRef::Int16(values),
MultiValuesRepr::Int32(values) => MultiValuesRef::Int32(values),
MultiValuesRepr::Int64(values) => MultiValuesRef::Int64(values),
MultiValuesRepr::Int128(values) => MultiValuesRef::Int128(values),
MultiValuesRepr::UInt8(values) => MultiValuesRef::UInt8(values),
MultiValuesRepr::UInt16(values) => MultiValuesRef::UInt16(values),
MultiValuesRepr::UInt32(values) => MultiValuesRef::UInt32(values),
MultiValuesRepr::UInt64(values) => MultiValuesRef::UInt64(values),
MultiValuesRepr::UInt128(values) => MultiValuesRef::UInt128(values),
MultiValuesRepr::Float32(values) => MultiValuesRef::Float32(values),
MultiValuesRepr::Float64(values) => MultiValuesRef::Float64(values),
#[cfg(feature = "big-integer")]
MultiValuesRepr::BigInteger(values) => {
MultiValuesRef::BigInteger(values)
}
#[cfg(feature = "big-decimal")]
MultiValuesRepr::BigDecimal(values) => {
MultiValuesRef::BigDecimal(values)
}
MultiValuesRepr::String(values) => MultiValuesRef::String(values),
#[cfg(feature = "chrono")]
MultiValuesRepr::Date(values) => MultiValuesRef::Date(values),
#[cfg(feature = "chrono")]
MultiValuesRepr::Time(values) => MultiValuesRef::Time(values),
#[cfg(feature = "chrono")]
MultiValuesRepr::DateTime(values) => {
MultiValuesRef::DateTime(values)
}
#[cfg(feature = "chrono")]
MultiValuesRepr::Instant(values) => MultiValuesRef::Instant(values),
MultiValuesRepr::Duration(values) => {
MultiValuesRef::Duration(values)
}
#[cfg(feature = "url")]
MultiValuesRepr::Url(values) => MultiValuesRef::Url(values),
MultiValuesRepr::StringMap(values) => {
MultiValuesRef::StringMap(values)
}
#[cfg(feature = "json")]
MultiValuesRepr::Json(values) => MultiValuesRef::Json(values),
}
}
}
macro_rules! impl_get_multi_values {
($(#[$attr:meta])* slice: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
$(#[$attr])*
#[doc = ""]
#[doc = "# Errors"]
#[doc = ""]
#[doc = "Returns [`ValueError::Missing`] when the container is unset"]
#[doc = "with the requested type, or [`ValueError::TypeMismatch`] when"]
#[doc = "the stored data type differs. A concrete empty vector returns"]
#[doc = "an empty slice."]
#[inline(always)]
pub fn $method(&self) -> ValueResult<&[$type]> {
match &self.repr {
MultiValuesRepr::$variant(v) => Ok(v),
MultiValuesRepr::Unset(dt) if *dt == $data_type => {
Err(ValueError::Missing($crate::ValueMissing::UnsetCollection {
data_type: *dt,
}))
}
_ => Err(ValueError::TypeMismatch {
expected: $data_type,
actual: self.data_type(),
}),
}
}
};
($(#[$attr:meta])* vec: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
$(#[$attr])*
#[doc = ""]
#[doc = "# Errors"]
#[doc = ""]
#[doc = "Returns [`ValueError::Missing`] when the container is unset"]
#[doc = "with the requested type, or [`ValueError::TypeMismatch`] when"]
#[doc = "the stored data type differs. A concrete empty vector returns"]
#[doc = "an empty slice."]
#[inline(always)]
pub fn $method(&self) -> ValueResult<&[$type]> {
match &self.repr {
MultiValuesRepr::$variant(v) => Ok(v.as_slice()),
MultiValuesRepr::Unset(dt) if *dt == $data_type => {
Err(ValueError::Missing($crate::ValueMissing::UnsetCollection {
data_type: *dt,
}))
}
_ => Err(ValueError::TypeMismatch {
expected: $data_type,
actual: self.data_type(),
}),
}
}
};
}
macro_rules! impl_get_first_value {
($(#[$attr:meta])* copy: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
$(#[$attr])*
#[doc = ""]
#[doc = "# Errors"]
#[doc = ""]
#[doc = "Returns [`ValueError::Missing`] when the requested type matches"]
#[doc = "but no value is stored, or [`ValueError::TypeMismatch`] when"]
#[doc = "the stored data type differs."]
#[inline(always)]
pub fn $method(&self) -> ValueResult<$type> {
match &self.repr {
MultiValuesRepr::$variant(v) if !v.is_empty() => Ok(v[0]),
MultiValuesRepr::$variant(_) => {
Err(ValueError::Missing($crate::ValueMissing::EmptyCollection {
data_type: $data_type,
}))
}
MultiValuesRepr::Unset(dt) if *dt == $data_type => {
Err(ValueError::Missing($crate::ValueMissing::UnsetCollection {
data_type: *dt,
}))
}
_ => Err(ValueError::TypeMismatch {
expected: $data_type,
actual: self.data_type(),
}),
}
}
};
($(#[$attr:meta])* ref: $method:ident, $variant:ident, $ret_type:ty, $data_type:expr, $conversion:expr) => {
$(#[$attr])*
#[doc = ""]
#[doc = "# Errors"]
#[doc = ""]
#[doc = "Returns [`ValueError::Missing`] when the requested type matches"]
#[doc = "but no value is stored, or [`ValueError::TypeMismatch`] when"]
#[doc = "the stored data type differs."]
#[inline(always)]
pub fn $method(&self) -> ValueResult<$ret_type> {
match &self.repr {
MultiValuesRepr::$variant(v) if !v.is_empty() => {
let conv_fn: fn(&_) -> $ret_type = $conversion;
Ok(conv_fn(&v[0]))
},
MultiValuesRepr::$variant(_) => {
Err(ValueError::Missing($crate::ValueMissing::EmptyCollection {
data_type: $data_type,
}))
}
MultiValuesRepr::Unset(dt) if *dt == $data_type => {
Err(ValueError::Missing($crate::ValueMissing::UnsetCollection {
data_type: *dt,
}))
}
_ => Err(ValueError::TypeMismatch {
expected: $data_type,
actual: self.data_type(),
}),
}
}
};
}