use super::super::Data;
use super::Value;
use std::sync::Arc;
pub trait GetData<T>: Sized {
fn try_data(self) -> Result<T, ()>;
}
impl GetData<Value> for Value {
fn try_data(self) -> Result<Value, ()> {
Ok(self)
}
}
impl From<()> for Value {
fn from(value: ()) -> Self {
Value::Void(value)
}
}
impl GetData<()> for Value {
fn try_data(self) -> Result<(), ()> {
match self {
Value::Void(_) => Ok(()),
_ => Err(()),
}
}
}
impl From<i8> for Value {
fn from(value: i8) -> Self {
Value::I8(value)
}
}
impl GetData<i8> for Value {
fn try_data(self) -> Result<i8, ()> {
match self {
Value::I8(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<i16> for Value {
fn from(value: i16) -> Self {
Value::I16(value)
}
}
impl GetData<i16> for Value {
fn try_data(self) -> Result<i16, ()> {
match self {
Value::I16(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<i32> for Value {
fn from(value: i32) -> Self {
Value::I32(value)
}
}
impl GetData<i32> for Value {
fn try_data(self) -> Result<i32, ()> {
match self {
Value::I32(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<i64> for Value {
fn from(value: i64) -> Self {
Value::I64(value)
}
}
impl GetData<i64> for Value {
fn try_data(self) -> Result<i64, ()> {
match self {
Value::I64(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<i128> for Value {
fn from(value: i128) -> Self {
Value::I128(value)
}
}
impl GetData<i128> for Value {
fn try_data(self) -> Result<i128, ()> {
match self {
Value::I128(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<u8> for Value {
fn from(value: u8) -> Self {
Value::U8(value)
}
}
impl GetData<u8> for Value {
fn try_data(self) -> Result<u8, ()> {
match self {
Value::U8(val) => Ok(val),
Value::Byte(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<u16> for Value {
fn from(value: u16) -> Self {
Value::U16(value)
}
}
impl GetData<u16> for Value {
fn try_data(self) -> Result<u16, ()> {
match self {
Value::U16(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<u32> for Value {
fn from(value: u32) -> Self {
Value::U32(value)
}
}
impl GetData<u32> for Value {
fn try_data(self) -> Result<u32, ()> {
match self {
Value::U32(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<u64> for Value {
fn from(value: u64) -> Self {
Value::U64(value)
}
}
impl GetData<u64> for Value {
fn try_data(self) -> Result<u64, ()> {
match self {
Value::U64(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<u128> for Value {
fn from(value: u128) -> Self {
Value::U128(value)
}
}
impl GetData<u128> for Value {
fn try_data(self) -> Result<u128, ()> {
match self {
Value::U128(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<f32> for Value {
fn from(value: f32) -> Self {
Value::F32(value)
}
}
impl GetData<f32> for Value {
fn try_data(self) -> Result<f32, ()> {
match self {
Value::F32(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Value::F64(value)
}
}
impl GetData<f64> for Value {
fn try_data(self) -> Result<f64, ()> {
match self {
Value::F64(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Value::Bool(value)
}
}
impl GetData<bool> for Value {
fn try_data(self) -> Result<bool, ()> {
match self {
Value::Bool(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<char> for Value {
fn from(value: char) -> Self {
Value::Char(value)
}
}
impl GetData<char> for Value {
fn try_data(self) -> Result<char, ()> {
match self {
Value::Char(val) => Ok(val),
_ => Err(()),
}
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Value::String(value)
}
}
impl GetData<String> for Value {
fn try_data(self) -> Result<String, ()> {
match self {
Value::String(val) => Ok(val),
_ => Err(()),
}
}
}
impl<T: Into<Value>> From<Option<T>> for Value {
fn from(value: Option<T>) -> Self {
Value::Option(value.map(|val| Box::new(val.into())))
}
}
impl<T> GetData<Option<T>> for Value
where
Self: GetData<T>,
{
fn try_data(self) -> Result<Option<T>, ()> {
match self {
Value::Option(val) => {
if let Some(val) = val {
match val.try_data() {
Ok(val) => Ok(Some(val)),
Err(_) => Err(()),
}
} else {
Ok(None)
}
}
_ => Err(()),
}
}
}
impl<T: Into<Value> + 'static> From<Vec<T>> for Value {
fn from(value: Vec<T>) -> Self {
match super::PackedArray::try_from_vec(value) {
Ok(packed) => Value::Packed(packed),
Err(value) => Value::Vec(value.into_iter().map(|val| val.into()).collect()),
}
}
}
impl<T: 'static> GetData<Vec<T>> for Value
where
Self: GetData<T>,
{
fn try_data(self) -> Result<Vec<T>, ()> {
match self {
Value::Vec(val) => {
let mut result = Vec::with_capacity(val.len());
for val in val {
match val.try_data() {
Ok(val) => result.push(val),
Err(_) => return Err(()),
}
}
Ok(result)
}
Value::Packed(arr) => match arr.try_into_vec() {
Ok(vec) => Ok(vec),
Err(arr) => {
let val = arr.into_values();
let mut result = Vec::with_capacity(val.len());
for val in val {
match val.try_data() {
Ok(val) => result.push(val),
Err(_) => return Err(()),
}
}
Ok(result)
}
},
_ => Err(()),
}
}
}
impl From<Arc<dyn Data>> for Value {
fn from(value: Arc<dyn Data>) -> Self {
Value::Data(value)
}
}
impl GetData<Arc<dyn Data>> for Value {
fn try_data(self) -> Result<Arc<dyn Data>, ()> {
match self {
Value::Data(val) => Ok(val),
_ => Err(()),
}
}
}
impl<D: Data> GetData<Arc<D>> for Value {
fn try_data(self) -> Result<Arc<D>, ()> {
let data: Arc<dyn Data> = GetData::<Arc<dyn Data>>::try_data(self)?;
data.downcast_arc::<D>().map_err(|_| ())
}
}
#[cfg(test)]
mod arc_data_getdata_tests {
use super::*;
fn _assert_composes<D: Data>()
where
Value: GetData<Vec<Arc<D>>> + GetData<Option<Arc<D>>> + GetData<Vec<Option<Arc<D>>>>,
{
}
}
#[cfg(test)]
mod auto_packing_tests {
use super::*;
use crate::executive::PackedArray;
#[test]
fn into_produces_packed_for_a_packable_primitive() {
let value: Value = vec![1u8, 2, 3].into();
assert!(matches!(value, Value::Packed(PackedArray::U8(_))));
}
#[test]
fn into_still_produces_the_boxed_form_for_a_non_packable_type() {
let value: Value = vec!["a".to_string(), "b".to_string()].into();
assert!(matches!(value, Value::Vec(_)));
}
#[test]
fn value_extracts_to_itself() {
let value = Value::U64(42);
let extracted: Value = value.clone().try_data().unwrap();
assert_eq!(extracted, value);
}
#[test]
fn vec_of_value_extracts_correctly_from_a_packed_source() {
let value = Value::Packed(PackedArray::I64(Arc::new(vec![1, 2, 3])));
let extracted: Vec<Value> = value.try_data().unwrap();
assert_eq!(extracted, vec![Value::I64(1), Value::I64(2), Value::I64(3)]);
}
#[test]
fn vec_of_value_still_extracts_correctly_from_a_boxed_source() {
let value = Value::Vec(vec![Value::I64(1), Value::I64(2)]);
let extracted: Vec<Value> = value.try_data().unwrap();
assert_eq!(extracted, vec![Value::I64(1), Value::I64(2)]);
}
#[test]
fn into_auto_packs_through_nested_option() {
let value: Value = Some(vec![1u8, 2, 3]).into();
match value {
Value::Option(Some(inner)) => {
assert!(matches!(*inner, Value::Packed(PackedArray::U8(_))));
}
other => panic!(
"expected Value::Option(Some(Value::Packed(_))), got {:?}",
other
),
}
}
#[test]
fn auto_packed_value_extracts_correctly_both_ways() {
let value: Value = vec![1u8, 2, 3].into();
let as_vec: Vec<u8> = value.clone().try_data().unwrap();
assert_eq!(as_vec, vec![1, 2, 3]);
let as_arc: Arc<Vec<u8>> = value.try_data().unwrap();
assert_eq!(*as_arc, vec![1, 2, 3]);
}
}