#[cfg(test)]
use assert_order::VariantOrder;
use std::borrow::Cow;
#[cfg(feature = "owned")]
use yoke::Yokeable;
#[cfg(feature = "owned")]
mod owned;
#[cfg(feature = "owned")]
pub use owned::OwnedDataCell;
const F32_MAX_EXACT_INTEGER: i32 = (1 << f32::MANTISSA_DIGITS) - 1;
const F32_MIN_EXACT_INTEGER: i32 = -F32_MAX_EXACT_INTEGER;
const F64_MAX_EXACT_INTEGER: i64 = (1 << f64::MANTISSA_DIGITS) - 1;
const F64_MIN_EXACT_INTEGER: i64 = -F64_MAX_EXACT_INTEGER;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "owned", derive(Yokeable))]
#[cfg_attr(test, derive(VariantOrder))]
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum DataCell<'d> {
Empty,
Text(Cow<'d, str>),
Bytes(Cow<'d, [u8]>),
Unsigned8(u8),
Unsigned16(u16),
Unsigned32(u32),
Unsigned64(u64),
Unsigned128(u128),
Signed8(i8),
Signed16(i16),
Signed32(i32),
Signed64(i64),
Signed128(i128),
Float32(f32),
Float64(f64),
}
#[cfg(feature = "owned")]
impl<B> PartialEq<owned::OwnedDataCell<B>> for DataCell<'_> {
fn eq(&self, other: &owned::OwnedDataCell<B>) -> bool {
self == other.yoke.get()
}
}
impl<'d> DataCell<'d> {
pub fn cloned(&self) -> DataCell<'static> {
match self {
Self::Empty => DataCell::Empty,
Self::Text(text) => DataCell::Text(Cow::Owned(text.to_string())),
Self::Bytes(bytes) => DataCell::Bytes(Cow::Owned(bytes.to_vec())),
Self::Unsigned8(num) => DataCell::u8(*num),
Self::Unsigned16(num) => DataCell::u16(*num),
Self::Unsigned32(num) => DataCell::u32(*num),
Self::Unsigned64(num) => DataCell::u64(*num),
Self::Unsigned128(num) => DataCell::u128(*num),
Self::Signed8(num) => DataCell::i8(*num),
Self::Signed16(num) => DataCell::i16(*num),
Self::Signed32(num) => DataCell::i32(*num),
Self::Signed64(num) => DataCell::i64(*num),
Self::Signed128(num) => DataCell::i128(*num),
Self::Float32(num) => DataCell::f32(*num),
Self::Float64(num) => DataCell::f64(*num),
}
}
pub fn empty() -> Self {
Self::Empty
}
pub fn text(value: impl Into<Cow<'d, str>>) -> Self {
Self::Text(value.into())
}
pub fn as_text(&self) -> Option<&str> {
if let Self::Text(text) = self {
Some(text)
} else {
None
}
}
pub fn try_as_text(&self) -> Option<&str> {
match self {
Self::Text(text) => Some(text),
Self::Bytes(bytes) => std::str::from_utf8(bytes).ok(),
_ => None,
}
}
pub fn bytes(value: impl Into<Cow<'d, [u8]>>) -> Self {
Self::Bytes(value.into())
}
pub fn as_bytes(&self) -> Option<&[u8]> {
if let Self::Bytes(bytes) = self {
Some(bytes)
} else {
None
}
}
pub fn try_as_bytes(&self) -> Option<&[u8]> {
match self {
Self::Bytes(bytes) => Some(bytes),
Self::Text(text) => Some(text.as_bytes()),
_ => None,
}
}
pub fn u8(value: u8) -> Self {
Self::Unsigned8(value)
}
pub fn as_u8(&self) -> Option<u8> {
if let Self::Unsigned8(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_u8(&self) -> Option<u8> {
match self {
Self::Unsigned8(num) => Some(*num),
Self::Unsigned16(num) => u8::try_from(*num).ok(),
Self::Unsigned32(num) => u8::try_from(*num).ok(),
Self::Unsigned64(num) => u8::try_from(*num).ok(),
Self::Unsigned128(num) => u8::try_from(*num).ok(),
Self::Signed8(num) => u8::try_from(*num).ok(),
Self::Signed16(num) => u8::try_from(*num).ok(),
Self::Signed32(num) => u8::try_from(*num).ok(),
Self::Signed64(num) => u8::try_from(*num).ok(),
Self::Signed128(num) => u8::try_from(*num).ok(),
Self::Float32(num) => {
let num = *num;
if (0.0..=255.0).contains(&num) && num.trunc() == num {
Some(num as u8)
} else {
None
}
}
Self::Float64(num) => {
let num = *num;
if (0.0..=255.0).contains(&num) && num.trunc() == num {
Some(num as u8)
} else {
None
}
}
_ => None,
}
}
pub fn u16(value: u16) -> Self {
Self::Unsigned16(value)
}
pub fn as_u16(&self) -> Option<u16> {
if let Self::Unsigned16(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_u16(&self) -> Option<u16> {
match self {
Self::Unsigned8(num) => Some(*num as u16),
Self::Unsigned16(num) => Some(*num),
Self::Unsigned32(num) => u16::try_from(*num).ok(),
Self::Unsigned64(num) => u16::try_from(*num).ok(),
Self::Unsigned128(num) => u16::try_from(*num).ok(),
Self::Signed8(num) => u16::try_from(*num).ok(),
Self::Signed16(num) => u16::try_from(*num).ok(),
Self::Signed32(num) => u16::try_from(*num).ok(),
Self::Signed64(num) => u16::try_from(*num).ok(),
Self::Signed128(num) => u16::try_from(*num).ok(),
Self::Float32(num) => {
let num = *num;
if num >= 0.0 && num <= (u16::MAX as f32) && num.trunc() == num {
Some(num as u16)
} else {
None
}
}
Self::Float64(num) => {
let num = *num;
if num >= 0.0 && num <= (u16::MAX as f64) && num.trunc() == num {
Some(num as u16)
} else {
None
}
}
_ => None,
}
}
pub fn u32(value: u32) -> Self {
Self::Unsigned32(value)
}
pub fn as_u32(&self) -> Option<u32> {
if let Self::Unsigned32(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_u32(&self) -> Option<u32> {
match self {
Self::Unsigned8(num) => Some(*num as u32),
Self::Unsigned16(num) => Some(*num as u32),
Self::Unsigned32(num) => Some(*num),
Self::Unsigned64(num) => u32::try_from(*num).ok(),
Self::Unsigned128(num) => u32::try_from(*num).ok(),
Self::Signed8(num) => u32::try_from(*num).ok(),
Self::Signed16(num) => u32::try_from(*num).ok(),
Self::Signed32(num) => u32::try_from(*num).ok(),
Self::Signed64(num) => u32::try_from(*num).ok(),
Self::Signed128(num) => u32::try_from(*num).ok(),
Self::Float32(num) => {
let num = *num;
if num >= 0.0 && num <= (F32_MAX_EXACT_INTEGER as f32) && num.trunc() == num {
Some(num as u32)
} else {
None
}
}
Self::Float64(num) => {
let num = *num;
if num >= 0.0 && num <= (u32::MAX as f64) && num.trunc() == num {
Some(num as u32)
} else {
None
}
}
_ => None,
}
}
pub fn u64(value: u64) -> Self {
Self::Unsigned64(value)
}
pub fn as_u64(&self) -> Option<u64> {
if let Self::Unsigned64(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_u64(&self) -> Option<u64> {
match self {
Self::Unsigned8(num) => Some(*num as u64),
Self::Unsigned16(num) => Some(*num as u64),
Self::Unsigned32(num) => Some(*num as u64),
Self::Unsigned64(num) => Some(*num),
Self::Unsigned128(num) => u64::try_from(*num).ok(),
Self::Signed8(num) => u64::try_from(*num).ok(),
Self::Signed16(num) => u64::try_from(*num).ok(),
Self::Signed32(num) => u64::try_from(*num).ok(),
Self::Signed64(num) => u64::try_from(*num).ok(),
Self::Signed128(num) => u64::try_from(*num).ok(),
Self::Float32(num) => {
let num = *num;
if num >= 0.0 && num <= (F32_MAX_EXACT_INTEGER as f32) && num.trunc() == num {
Some(num as u64)
} else {
None
}
}
Self::Float64(num) => {
let num = *num;
if num >= 0.0 && num <= (F64_MAX_EXACT_INTEGER as f64) && num.trunc() == num {
Some(num as u64)
} else {
None
}
}
_ => None,
}
}
pub fn u128(value: u128) -> Self {
Self::Unsigned128(value)
}
pub fn as_u128(&self) -> Option<u128> {
if let Self::Unsigned128(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_u128(&self) -> Option<u128> {
match self {
Self::Unsigned8(num) => Some(*num as u128),
Self::Unsigned16(num) => Some(*num as u128),
Self::Unsigned32(num) => Some(*num as u128),
Self::Unsigned64(num) => Some(*num as u128),
Self::Unsigned128(num) => Some(*num),
Self::Signed8(num) => u128::try_from(*num).ok(),
Self::Signed16(num) => u128::try_from(*num).ok(),
Self::Signed32(num) => u128::try_from(*num).ok(),
Self::Signed64(num) => u128::try_from(*num).ok(),
Self::Signed128(num) => u128::try_from(*num).ok(),
Self::Float32(num) => {
let num = *num;
if num >= 0.0 && num <= (F32_MAX_EXACT_INTEGER as f32) && num.trunc() == num {
Some(num as u128)
} else {
None
}
}
Self::Float64(num) => {
let num = *num;
if num >= 0.0 && num <= (F64_MAX_EXACT_INTEGER as f64) && num.trunc() == num {
Some(num as u128)
} else {
None
}
}
_ => None,
}
}
pub fn i8(value: i8) -> Self {
Self::Signed8(value)
}
pub fn as_i8(&self) -> Option<i8> {
if let Self::Signed8(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_i8(&self) -> Option<i8> {
match self {
Self::Signed8(num) => Some(*num),
Self::Signed16(num) => i8::try_from(*num).ok(),
Self::Signed32(num) => i8::try_from(*num).ok(),
Self::Signed64(num) => i8::try_from(*num).ok(),
Self::Signed128(num) => i8::try_from(*num).ok(),
Self::Unsigned8(num) => i8::try_from(*num).ok(),
Self::Unsigned16(num) => i8::try_from(*num).ok(),
Self::Unsigned32(num) => i8::try_from(*num).ok(),
Self::Unsigned64(num) => i8::try_from(*num).ok(),
Self::Unsigned128(num) => i8::try_from(*num).ok(),
Self::Float32(num) => {
let num = *num;
if num >= (i8::MIN as f32) && num <= (i8::MAX as f32) && num.trunc() == num {
Some(num as i8)
} else {
None
}
}
Self::Float64(num) => {
let num = *num;
if num >= (i8::MIN as f64) && num <= (i8::MAX as f64) && num.trunc() == num {
Some(num as i8)
} else {
None
}
}
_ => None,
}
}
pub fn i16(value: i16) -> Self {
Self::Signed16(value)
}
pub fn as_i16(&self) -> Option<i16> {
if let Self::Signed16(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_i16(&self) -> Option<i16> {
match self {
Self::Signed8(num) => Some(*num as i16),
Self::Signed16(num) => Some(*num),
Self::Signed32(num) => i16::try_from(*num).ok(),
Self::Signed64(num) => i16::try_from(*num).ok(),
Self::Signed128(num) => i16::try_from(*num).ok(),
Self::Unsigned8(num) => Some(i16::from(*num)),
Self::Unsigned16(num) => i16::try_from(*num).ok(),
Self::Unsigned32(num) => i16::try_from(*num).ok(),
Self::Unsigned64(num) => i16::try_from(*num).ok(),
Self::Unsigned128(num) => i16::try_from(*num).ok(),
Self::Float32(num) => {
let num = *num;
if num >= (i16::MIN as f32) && num <= (i16::MAX as f32) && num.trunc() == num {
Some(num as i16)
} else {
None
}
}
Self::Float64(num) => {
let num = *num;
if num >= (i16::MIN as f64) && num <= (i16::MAX as f64) && num.trunc() == num {
Some(num as i16)
} else {
None
}
}
_ => None,
}
}
pub fn i32(value: i32) -> Self {
Self::Signed32(value)
}
pub fn as_i32(&self) -> Option<i32> {
if let Self::Signed32(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_i32(&self) -> Option<i32> {
match self {
Self::Signed8(num) => Some(*num as i32),
Self::Signed16(num) => Some(*num as i32),
Self::Signed32(num) => Some(*num),
Self::Signed64(num) => i32::try_from(*num).ok(),
Self::Signed128(num) => i32::try_from(*num).ok(),
Self::Unsigned8(num) => Some(i32::from(*num)),
Self::Unsigned16(num) => Some(i32::from(*num)),
Self::Unsigned32(num) => i32::try_from(*num).ok(),
Self::Unsigned64(num) => i32::try_from(*num).ok(),
Self::Unsigned128(num) => i32::try_from(*num).ok(),
Self::Float32(num) => {
let num = *num;
if num >= (F32_MIN_EXACT_INTEGER as f32)
&& num <= (F32_MAX_EXACT_INTEGER as f32)
&& num.trunc() == num
{
Some(num as i32)
} else {
None
}
}
Self::Float64(num) => {
let num = *num;
if num >= (i32::MIN as f64) && num <= (i32::MAX as f64) && num.trunc() == num {
Some(num as i32)
} else {
None
}
}
_ => None,
}
}
pub fn i64(value: i64) -> Self {
Self::Signed64(value)
}
pub fn as_i64(&self) -> Option<i64> {
if let Self::Signed64(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_i64(&self) -> Option<i64> {
match self {
Self::Signed8(num) => Some(*num as i64),
Self::Signed16(num) => Some(*num as i64),
Self::Signed32(num) => Some(*num as i64),
Self::Signed64(num) => Some(*num),
Self::Signed128(num) => i64::try_from(*num).ok(),
Self::Unsigned8(num) => Some(i64::from(*num)),
Self::Unsigned16(num) => Some(i64::from(*num)),
Self::Unsigned32(num) => Some(i64::from(*num)),
Self::Unsigned64(num) => i64::try_from(*num).ok(),
Self::Unsigned128(num) => i64::try_from(*num).ok(),
Self::Float32(num) => {
let num = *num;
if num >= (F32_MIN_EXACT_INTEGER as f32)
&& num <= (F32_MAX_EXACT_INTEGER as f32)
&& num.trunc() == num
{
Some(num as i64)
} else {
None
}
}
Self::Float64(num) => {
let num = *num;
if num >= (F64_MIN_EXACT_INTEGER as f64)
&& num <= (F64_MAX_EXACT_INTEGER as f64)
&& num.trunc() == num
{
Some(num as i64)
} else {
None
}
}
_ => None,
}
}
pub fn i128(value: i128) -> Self {
Self::Signed128(value)
}
pub fn as_i128(&self) -> Option<i128> {
if let Self::Signed128(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_i128(&self) -> Option<i128> {
match self {
Self::Signed8(num) => Some(*num as i128),
Self::Signed16(num) => Some(*num as i128),
Self::Signed32(num) => Some(*num as i128),
Self::Signed64(num) => Some(*num as i128),
Self::Signed128(num) => Some(*num),
Self::Unsigned8(num) => Some(i128::from(*num)),
Self::Unsigned16(num) => Some(i128::from(*num)),
Self::Unsigned32(num) => Some(i128::from(*num)),
Self::Unsigned64(num) => Some(i128::from(*num)),
Self::Unsigned128(num) => i128::try_from(*num).ok(),
Self::Float32(num) => {
let num = *num;
if num >= (F32_MIN_EXACT_INTEGER as f32)
&& num <= (F32_MAX_EXACT_INTEGER as f32)
&& num.trunc() == num
{
Some(num as i128)
} else {
None
}
}
Self::Float64(num) => {
let num = *num;
if num >= (F64_MIN_EXACT_INTEGER as f64)
&& num <= (F64_MAX_EXACT_INTEGER as f64)
&& num.trunc() == num
{
Some(num as i128)
} else {
None
}
}
_ => None,
}
}
pub fn f32(value: f32) -> Self {
Self::Float32(value)
}
pub fn as_f32(&self) -> Option<f32> {
if let Self::Float32(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_f32(&self) -> Option<f32> {
match self {
Self::Float32(num) => Some(*num),
Self::Float64(_num) => None,
Self::Unsigned8(num) => Some(f32::from(*num)),
Self::Unsigned16(num) => Some(f32::from(*num)),
Self::Unsigned32(num) => {
let num = i32::try_from(*num).ok()?;
if (F32_MIN_EXACT_INTEGER..=F32_MAX_EXACT_INTEGER).contains(&num) {
Some(num as f32)
} else {
None
}
}
Self::Unsigned64(num) => {
let num = i32::try_from(*num).ok()?;
if (F32_MIN_EXACT_INTEGER..=F32_MAX_EXACT_INTEGER).contains(&num) {
Some(num as f32)
} else {
None
}
}
Self::Unsigned128(num) => {
let num = i32::try_from(*num).ok()?;
if (F32_MIN_EXACT_INTEGER..=F32_MAX_EXACT_INTEGER).contains(&num) {
Some(num as f32)
} else {
None
}
}
Self::Signed8(num) => Some(f32::from(*num)),
Self::Signed16(num) => Some(f32::from(*num)),
Self::Signed32(num) => {
let num = *num;
if (F32_MIN_EXACT_INTEGER..=F32_MAX_EXACT_INTEGER).contains(&num) {
Some(num as f32)
} else {
None
}
}
Self::Signed64(num) => {
let num = *num;
if num >= i64::from(F32_MIN_EXACT_INTEGER)
&& num <= i64::from(F32_MAX_EXACT_INTEGER)
{
Some(num as f32)
} else {
None
}
}
Self::Signed128(num) => {
let num = *num;
if num >= i128::from(F32_MIN_EXACT_INTEGER)
&& num <= i128::from(F32_MAX_EXACT_INTEGER)
{
Some(num as f32)
} else {
None
}
}
_ => None,
}
}
pub fn f64(value: f64) -> Self {
Self::Float64(value)
}
pub fn as_f64(&self) -> Option<f64> {
if let Self::Float64(num) = self {
Some(*num)
} else {
None
}
}
pub fn try_as_f64(&self) -> Option<f64> {
match self {
Self::Float32(num) => Some(f64::from(*num)),
Self::Float64(num) => Some(*num),
Self::Unsigned8(num) => Some(f64::from(*num)),
Self::Unsigned16(num) => Some(f64::from(*num)),
Self::Unsigned32(num) => Some(f64::from(*num)),
Self::Unsigned64(num) => {
let num = i64::try_from(*num).ok()?;
if (F64_MIN_EXACT_INTEGER..=F64_MAX_EXACT_INTEGER).contains(&num) {
Some(num as f64)
} else {
None
}
}
Self::Unsigned128(num) => {
let num = i64::try_from(*num).ok()?;
if (F64_MIN_EXACT_INTEGER..=F64_MAX_EXACT_INTEGER).contains(&num) {
Some(num as f64)
} else {
None
}
}
Self::Signed8(num) => Some(f64::from(*num)),
Self::Signed16(num) => Some(f64::from(*num)),
Self::Signed32(num) => Some(f64::from(*num)),
Self::Signed64(num) => {
let num = *num;
if (F64_MIN_EXACT_INTEGER..=F64_MAX_EXACT_INTEGER).contains(&num) {
Some(num as f64)
} else {
None
}
}
Self::Signed128(num) => {
let num = *num;
if num >= i128::from(F64_MIN_EXACT_INTEGER)
&& num <= i128::from(F64_MAX_EXACT_INTEGER)
{
Some(num as f64)
} else {
None
}
}
_ => None,
}
}
}
impl From<()> for DataCell<'static> {
fn from(_value: ()) -> Self {
Self::Empty
}
}
impl From<String> for DataCell<'static> {
fn from(value: String) -> Self {
Self::Text(Cow::from(value))
}
}
impl From<Box<str>> for DataCell<'static> {
fn from(value: Box<str>) -> Self {
Self::Text(Cow::from(value.into_string()))
}
}
impl<'a> From<&'a str> for DataCell<'a> {
fn from(value: &'a str) -> Self {
Self::Text(Cow::Borrowed(value))
}
}
impl From<Vec<u8>> for DataCell<'static> {
fn from(value: Vec<u8>) -> Self {
Self::Bytes(Cow::from(value))
}
}
impl From<Box<[u8]>> for DataCell<'static> {
fn from(value: Box<[u8]>) -> Self {
Self::Bytes(Cow::from(value.into_vec()))
}
}
impl<'a> From<&'a [u8]> for DataCell<'a> {
fn from(value: &'a [u8]) -> Self {
Self::Bytes(Cow::Borrowed(value))
}
}
impl From<u8> for DataCell<'static> {
fn from(value: u8) -> Self {
Self::Unsigned8(value)
}
}
impl From<u16> for DataCell<'static> {
fn from(value: u16) -> Self {
Self::Unsigned16(value)
}
}
impl From<u32> for DataCell<'static> {
fn from(value: u32) -> Self {
Self::Unsigned32(value)
}
}
impl From<u64> for DataCell<'static> {
fn from(value: u64) -> Self {
Self::Unsigned64(value)
}
}
impl From<u128> for DataCell<'static> {
fn from(value: u128) -> Self {
Self::Unsigned128(value)
}
}
impl From<i8> for DataCell<'static> {
fn from(value: i8) -> Self {
Self::Signed8(value)
}
}
impl From<i16> for DataCell<'static> {
fn from(value: i16) -> Self {
Self::Signed16(value)
}
}
impl From<i32> for DataCell<'static> {
fn from(value: i32) -> Self {
Self::Signed32(value)
}
}
impl From<i64> for DataCell<'static> {
fn from(value: i64) -> Self {
Self::Signed64(value)
}
}
impl From<i128> for DataCell<'static> {
fn from(value: i128) -> Self {
Self::Signed128(value)
}
}
impl From<f32> for DataCell<'static> {
fn from(value: f32) -> Self {
Self::Float32(value)
}
}
impl From<f64> for DataCell<'static> {
fn from(value: f64) -> Self {
Self::Float64(value)
}
}
#[cfg(test)]
mod tests {
use crate::DataCell;
use assert_order::assert_order;
#[test]
fn proper_order() {
assert_order::<DataCell, _, _>([
"Empty",
"Text",
"Bytes",
"Unsigned8",
"Unsigned16",
"Unsigned32",
"Unsigned64",
"Unsigned128",
"Signed8",
"Signed16",
"Signed32",
"Signed64",
"Signed128",
"Float32",
"Float64",
]);
}
}